initial sveltekit setup

This commit is contained in:
ngn 2023-08-20 00:57:35 +03:00
parent f7f008cc89
commit 195e4c7e02
76 changed files with 2054 additions and 28126 deletions

View File

@ -1,13 +0,0 @@
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

98
.gitignore vendored
View File

@ -1,90 +1,10 @@
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
# Service worker
sw.*
# macOS
.DS_Store
# Vim swap files
*.swp
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
engine-strict=true
resolution-mode=highest

View File

@ -1 +0,0 @@
.nuxt

View File

@ -1,6 +0,0 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"singleQuote": false
}

View File

@ -1,17 +1,38 @@
# My Website | [ngn13.fun](https://ngn13.fun)
This repo contains the source code of my personal website.
It's written NuxtJS and supports full SSR. As database,
it uses mongodb. It's just a personal project that
I am working on.
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
## Setup
For some reason if you want to setup my website localy
install `nodejs` and `npm`, then run the following:
```bash
git clone https://github.com/ngn13/ngn13.fun.git && cd ngn13.fun &&
npm i
echo "PASS=password" > .env
echo "DATABASE=mongodb://127.0.0.1" > .env
npm run build
npm run start
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

View File

@ -1,46 +0,0 @@
const express = require("express")
const { MongoClient } = require("mongodb")
require("dotenv").config()
/*
* error: 0 -> no error
* error: 1 -> parameter error
* error: 2 -> auth error
* error: 3 -> not found error
*/
const db = new MongoClient(process.env.DATABASE)
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(async (req, res, next) => {
await db.connect()
req.db = db
next()
})
const { auth, authware } = require("./routes/auth.js")
// anything starts with "add"
// requires admin privs
app.use("/*/a*", authware)
const resources = require("./routes/resources.js")
const projects = require("./routes/projects.js")
const blog = require("./routes/blog.js")
const routes = [resources, projects, blog, auth]
routes.forEach((route) => {
app.use(route.path, route)
})
async function pexit() {
await db.close()
process.exit()
}
process.on("SIGTERM", pexit)
process.on("SIGINT", pexit)
export default {
path: "/api",
handler: app
}

View File

@ -1,35 +0,0 @@
const express = require("express")
const { gimmeToken } = require("../util.js")
const auth = express.Router()
auth.path = "/auth"
const PASS = process.env.PASS
let TOKEN = gimmeToken()
function authware(req, res, next) {
const token = req.query.token ? req.query.token : req.body.token
if (typeof token !== "string") return res.json({ error: 1 })
if (token !== TOKEN) return res.json({ error: 2 })
next()
}
auth.use("/logout", authware)
auth.get("/login", async (req, res) => {
const pass = req.query.pass
if (typeof pass !== "string") return res.json({ error: 1 })
if (pass !== PASS) return res.json({ error: 2 })
res.json({ error: 0, token: TOKEN })
})
auth.get("/logout", async (req, res) => {
TOKEN = gimmeToken()
res.json({ error: 0 })
})
module.exports = { auth, authware }

View File

@ -1,87 +0,0 @@
const express = require("express")
const { makeID } = require("../util.js")
const blog = express.Router()
blog.path = "/blog"
blog.get("/sum", async (req, res) => {
const db = req.db.db("ngn13")
const col = db.collection("posts")
const results = await col.find({ priv: { $eq: false } }).toArray()
let posts = []
for (let i = 0; i < results.length; i++) {
posts.push({
title: results[i]["title"],
desc:
results[i]["content"]
.substring(0, 140) // a short desc
.replaceAll("#", "") // remove all the markdown stuff
.replaceAll("*", "")
.replaceAll("`", "")
.replaceAll("-", "") + "...", // add "..." to make it look like desc
info: `${results[i]["author"]} | ${results[i]["date"]}`
})
}
// reversing so we can get
// the latest posts on the top
res.json({ error: 0, posts: posts.reverse() })
})
blog.get("/get", async (req, res) => {
const id = req.query.id
const db = req.db.db("ngn13")
const col = db.collection("posts")
const results = await col.find().toArray()
for (let i = 0; i < results.length; i++) {
// id is basically the title of the post
// but ve remove the whitespace
// and make it lowerspace
// for example:
// Online Privacy Guide -> onlineprivacyguide
if (makeID(results[i]["title"]) === id) {
return res.json({
error: 0,
post: {
title: results[i]["title"],
// info is the subtitle, for example:
// ngn | 01/06/2023
info: `${results[i]["author"]} | ${results[i]["date"]}`,
content: results[i]["content"]
}
})
}
}
res.json({ error: 3 })
})
blog.post("/add", async (req, res) => {
const title = req.body.title
const author = req.body.author
const content = req.body.content
const priv = req.body.priv
if (
typeof title !== "string" ||
typeof author !== "string" ||
typeof content !== "string" ||
typeof priv !== "boolean"
)
return res.json({ error: 1 })
const db = req.db.db("ngn13")
const col = db.collection("posts")
await col.insertOne({
title: title,
author: author,
date: new Date().toLocaleDateString(),
content: content,
priv: priv
})
res.json({ error: 0 })
})
module.exports = blog

View File

@ -1,35 +0,0 @@
const express = require("express")
const projects = express.Router()
projects.path = "/projects"
projects.get("/get", async (req, res) => {
const db = req.db.db("ngn13")
const col = db.collection("projects")
const results = await col.find().toArray()
res.json({ error: 0, projects: results })
})
projects.get("/add", async (req, res) => {
let name = req.query.name
let desc = req.query.desc
let url = req.query.url
if (
typeof name !== "string" ||
typeof desc !== "string" ||
typeof url !== "string"
)
return res.json({ error: 1 })
const db = req.db.db("ngn13")
const col = db.collection("projects")
await col.insertOne({
name: name,
desc: desc,
url: url,
click: 0
})
res.json({ error: 0 })
})
module.exports = projects

View File

@ -1,32 +0,0 @@
const express = require("express")
const resources = express.Router()
resources.path = "/resources"
resources.get("/get", async (req, res) => {
const db = req.db.db("ngn13")
const col = db.collection("resources")
let results = []
if (req.query.sum) results = await col.find().limit(10).toArray()
else results = await col.find().toArray()
res.json({ error: 0, resources: results.reverse() })
})
resources.get("/add", async (req, res) => {
let name = req.query.name
let tags = req.query.tags
let url = req.query.url
if (
typeof name !== "string" ||
typeof tags !== "string" ||
typeof url !== "string"
)
return res.json({ error: 1 })
const db = req.db.db("ngn13")
const col = db.collection("resources")
await col.insertOne({ name: name, tags: tags.split(","), url: url })
res.json({ error: 0 })
})
module.exports = resources

View File

@ -1,22 +0,0 @@
function gimmeToken() {
var result = ""
var characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
var charactersLength = characters.length
for (var i = 0; i < 32; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength))
}
return result
}
function makeID(title) {
// this is used in blog.js
// id is basically the title of the post
// but ve remove the whitespace
// and make it lowerspace
// for example:
// Online Privacy Guide -> onlineprivacyguide
return title.toLowerCase().replaceAll(" ", "")
}
module.exports = { gimmeToken, makeID }

View File

@ -1,29 +0,0 @@
<template>
<button @click="click"><slot></slot></button>
</template>
<script>
export default {
props: ["click"]
}
</script>
<style scoped>
button {
text-align: center;
width: 540px;
font-size: 25px;
padding: 20px;
border-radius: 20px;
background: var(--dark-two);
border: none;
color: white;
outline: none;
cursor: pointer;
transition: 0.4s;
}
button:hover {
box-shadow: var(--def-shadow);
}
</style>

View File

@ -1,54 +0,0 @@
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
div {
box-shadow: var(--def-shadow);
background: var(--dark-two);
width: 100%;
height: auto;
padding: 50px;
color: white;
}
h1 {
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
font-size: 50px;
margin-bottom: 30px;
text-decoration: underline;
}
i {
animation-name: colorAnimation;
animation-duration: 10s;
animation-iteration-count: infinite;
}
a:hover {
font-weight: 900;
}
i {
font-size: 30px;
margin-top: 3px;
}
h2 {
font-size: 40px;
line-height: 60px;
}
a {
font-size: 40px;
color: white;
line-height: 60px;
text-decoration: none;
}
</style>

View File

@ -1,30 +0,0 @@
<template>
<div class="header">
<h1>
<slot></slot>
</h1>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
div {
background: linear-gradient(rgba(3, 3, 3, 0.706), rgba(22, 22, 22, 0.808)),
url("https://www.sketchappsources.com/resources/source-image/tv-glitch-sureshmurali29.png");
width: 100%;
height: 100%;
}
h1 {
font-weight: 900;
font-size: 7.5vw;
padding: 150px;
text-align: center;
color: white;
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
text-size-adjust: 80%;
}
</style>

View File

@ -1,27 +0,0 @@
<template>
<input v-on:keyup="keyup" :placeholder="placeholder" :type="type" />
</template>
<script>
export default {
props: ["keyup", "placeholder", "type"]
}
</script>
<style scoped>
input {
width: 500px;
font-size: 25px;
padding: 20px;
border-radius: 10px;
background: var(--dark-two);
border: none;
color: white;
outline: none;
transition: 0.4s;
}
input:focus {
box-shadow: var(--def-shadow);
}
</style>

View File

@ -1,41 +0,0 @@
<template>
<div>
<h1>Currently logged in</h1>
<Button :click="click">Logout</Button>
</div>
</template>
<script>
import axios from "axios"
import Button from "./Button.vue"
export default {
methods: {
async click(e) {
await axios.get(`/api/auth/logout?token=${localStorage.getItem("token")}`)
localStorage.clear()
location.reload()
}
}
}
</script>
<style scoped>
h1 {
color: var(--white);
font-size: 50px;
margin-bottom: 20px;
text-align: center;
}
div {
background-color: var(--dark-three);
padding: 50px;
margin-top: 50px;
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
justify-content: center;
}
</style>

View File

@ -1,55 +0,0 @@
<template>
<nav>
<div>
<h3>[ngn]</h3>
</div>
<div>
<NavbarLink :out="false" url="/">Home</NavbarLink>
<NavbarLink :out="false" url="/projects">Projects</NavbarLink>
<NavbarLink :out="false" url="/resources">Resources</NavbarLink>
<NavbarLink :out="false" url="/blog">Blog</NavbarLink>
<NavbarLink :out="true" url="http://github.com/ngn13/ngn13.fun"
>Source</NavbarLink
>
</div>
</nav>
</template>
<script>
import NavbarLink from "./NavbarLink.vue"
export default {}
</script>
<style scoped>
nav {
background: var(--dark-two);
padding: 25px 35px 30px 35px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
border-bottom: solid 3px black;
animation-name: borderAnimation;
animation-duration: 10s;
animation-iteration-count: infinite;
box-shadow: var(--def-shadow);
}
div {
display: flex;
overflow: hidden;
align-items: center;
justify-content: center;
gap: 5px;
}
h3 {
font-weight: 900;
font-size: 30px;
color: red;
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
}
</style>

View File

@ -1,60 +0,0 @@
<template>
<div>
<nuxt-link v-if="!out" :class="cname" id="link" :to="url">
<slot></slot>
</nuxt-link>
<a v-if="out" :class="cname" id="link" :href="url">
<slot></slot>
</a>
</div>
</template>
<script>
export default {
props: ["url", "out"],
data() {
return {
cname: "notcurrent"
}
},
mounted() {
let url = window.location.pathname
if (url === this.url) {
this.cname = "current"
}
}
}
</script>
<style scoped>
.notcurrent {
margin-left: 20px;
font-weight: 700;
font-size: 25px;
text-decoration: none;
color: white;
cursor: pointer;
}
.notcurrent:hover {
text-decoration: underline;
animation-name: underlineAnimation;
animation-duration: 5s;
animation-iteration-count: infinite;
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
}
.current {
margin-left: 20px;
font-weight: 700;
font-size: 25px;
text-decoration: none;
color: white;
cursor: pointer;
text-decoration: underline;
animation-name: underlineAnimation;
animation-duration: 10s;
animation-iteration-count: infinite;
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
}
</style>

View File

@ -1,123 +0,0 @@
<template>
<main>
<h1>Add New Post</h1>
<div class="textareas">
<Input
:keyup="function () {}"
id="title"
placeholder="Post Title"
type="text"
/>
<Input
:keyup="function () {}"
id="author"
placeholder="Author"
type="text"
/>
<h2>
Make the post private
<input id="private" type="checkbox" />
</h2>
</div>
<textarea
name="content"
id="content"
cols="30"
rows="10"
placeholder="Content"
></textarea>
<Button :click="click">Post</Button>
</main>
</template>
<script>
import axios from "axios"
import Input from "./Input.vue"
import Button from "./Button.vue"
export default {
methods: {
async click(e) {
const title = document.getElementById("title").value
const author = document.getElementById("author").value
const content = document.getElementById("content").value
const priv = document.getElementById("private").value
const token = localStorage.getItem("token")
const res = await axios.post("/api/blog/add", {
token: token,
title: title,
author: author,
content: content,
priv: priv === "on"
})
if (res.data["error"] !== 0) return alert("Error!")
alert("Post added!")
location.reload()
}
}
}
</script>
<style scoped>
h1 {
color: var(--white);
font-size: 50px;
margin-bottom: 20px;
text-align: center;
}
h2 {
background: var(--dark-two);
font-size: 25px;
border-radius: 20px;
border: none;
padding: 20px;
color: var(--white);
display: flex;
justify-content: space-between;
}
input[type="checkbox"] {
-ms-transform: scale(2);
-moz-transform: scale(2);
-webkit-transform: scale(2);
-o-transform: scale(2);
transform: scale(2);
padding: 10px;
}
textarea {
width: 500px;
font-size: 20px;
padding: 20px;
border-radius: 20px;
background: var(--dark-two);
border: none;
color: white;
outline: none;
resize: vertical;
height: 200px;
transition: 0.4s;
}
.textareas {
flex-direction: column;
display: flex;
gap: 20px;
}
textarea:focus {
box-shadow: var(--def-shadow);
}
main {
background-color: var(--dark-three);
padding: 50px;
margin-top: 50px;
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
justify-content: center;
}
</style>

View File

@ -1,67 +0,0 @@
<template>
<div>
<h1>Add Project</h1>
<Input
:keyup="function () {}"
id="name"
placeholder="Project Name"
type="text"
/>
<Input
:keyup="function () {}"
id="desc"
placeholder="Project Desc"
type="text"
/>
<Input
:keyup="function () {}"
id="url"
placeholder="Project URL"
type="text"
/>
<Button :click="click">Post</Button>
</div>
</template>
<script>
import axios from "axios"
import Input from "./Input.vue"
import Button from "./Button.vue"
export default {
methods: {
async click(e) {
const name = document.getElementById("name").value
const desc = document.getElementById("desc").value
const url = document.getElementById("url").value
const token = localStorage.getItem("token")
const res = await axios.get(
`/api/projects/add?token=${token}&name=${name}&desc=${desc}&url=${url}`
)
if (res.data["error"] !== 0) return alert("Error!")
alert("Project added!")
location.reload()
}
}
}
</script>
<style scoped>
h1 {
color: var(--white);
font-size: 50px;
margin-bottom: 20px;
text-align: center;
}
div {
background-color: var(--dark-three);
padding: 50px;
margin-top: 50px;
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
justify-content: center;
}
</style>

View File

@ -1,67 +0,0 @@
<template>
<div>
<h1>Add Resource</h1>
<Input
:keyup="function () {}"
id="name"
placeholder="Resource Name"
type="text"
/>
<Input
:keyup="function () {}"
id="tags"
placeholder="Resource Tags (comma seperated)"
type="text"
/>
<Input
:keyup="function () {}"
id="url"
placeholder="Resource URL"
type="text"
/>
<Button :click="click">Post</Button>
</div>
</template>
<script>
import Input from "./Input.vue"
import Button from "./Button.vue"
import axios from "axios"
export default {
methods: {
async click(e) {
const name = document.getElementById("name").value
const tags = document.getElementById("tags").value
const url = document.getElementById("url").value
const token = localStorage.getItem("token")
const res = await axios.get(
`/api/resources/add?token=${token}&name=${name}&tags=${tags}&url=${url}`
)
if (res.data["error"] !== 0) return alert("Error!")
alert("Resource added!")
location.reload()
}
}
}
</script>
<style scoped>
h1 {
color: var(--white);
font-size: 50px;
margin-bottom: 20px;
text-align: center;
}
div {
background-color: var(--dark-three);
padding: 50px;
margin-top: 50px;
display: flex;
flex-direction: column;
gap: 20px;
align-items: center;
justify-content: center;
}
</style>

View File

@ -1,42 +0,0 @@
<template>
<nuxt-link :to="url">
<h1>{{ title }}</h1>
<p>{{ info }}</p>
<h2>{{ desc }}</h2>
</nuxt-link>
</template>
<script>
export default {
props: ["title", "desc", "info", "url"]
}
</script>
<style scoped>
a {
padding: 30px;
color: white;
background: var(--dark-two);
cursor: pointer;
text-decoration: none;
transition: 0.4s;
width: 70%;
}
a:hover {
box-shadow: var(--def-shadow);
}
h1 {
font-size: 40px;
margin-bottom: 5px;
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
text-shadow: none;
}
h2 {
margin-top: 10px;
}
</style>

View File

@ -1,62 +0,0 @@
<template>
<main @click="redirect()">
<i class="bx bx-code-alt"></i>
<div>
<h1>{{ name }}</h1>
<h2>{{ desc }}</h2>
</div>
</main>
</template>
<script>
export default {
props: ["name", "desc", "url"],
methods: {
redirect(e) {
location.href = this.url
}
}
}
</script>
<style scoped>
main {
color: var(--white);
background: var(--dark-two);
display: flex;
flex-direction: row;
align-items: center;
gap: 20px;
padding: 40px;
cursor: pointer;
height: 100px;
width: 450px;
transition: .4s;
}
main:hover {
box-shadow: var(--def-shadow);
}
i {
font-size: 65px;
animation-name: colorAnimation;
animation-duration: 10s;
animation-iteration-count: infinite;
}
h1 {
font-size: 35px;
margin-bottom: 10px;
}
h2 {
font-size: 25px;
}
@media only screen and (max-width: 1416px) {
main {
width: 80%;
}
}
</style>

View File

@ -1,26 +0,0 @@
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
div {
display: flex;
flex-direction: row;
padding: 15px;
align-items: center;
justify-content: center;
gap: 30px;
}
@media only screen and (max-width: 1416px) {
div {
flex-direction: column;
}
}
</style>

View File

@ -1,66 +0,0 @@
<template>
<main @click="redirect()" class="mn">
<div class="resource">
<h1>{{ name }}</h1>
<div class="tags">
<Tag v-for="tag in tags" :key="tag">{{ tag }}</Tag>
</div>
</div>
<i class="bx bx-right-arrow-alt"></i>
</main>
</template>
<script>
import Tag from "./Tag.vue"
export default {
props: ["tags", "name", "url"],
methods: {
redirect(e) {
location.href = this.url
}
}
}
</script>
<style scoped>
main {
background: var(--dark-two);
padding: 30px 40px 30px 40px;
display: flex;
flex-direction: row;
color: var(--white);
justify-content: space-between;
align-items: center;
width: 80%;
cursor: pointer;
transition: .4s;
}
main:hover {
box-shadow: var(--def-shadow);
}
.mn:hover i {
color: white;
}
.resource {
display: flex;
flex-direction: column;
gap: 10px;
}
.tags {
display: flex;
flex-direction: row;
gap: 10px;
}
i {
font-size: 70px;
cursor: pointer;
color: var(--dark-two);
transition: 0.4s;
}
</style>

View File

@ -1,20 +0,0 @@
<template>
<p>#<slot></slot></p>
</template>
<script>
export default {}
</script>
<style scoped>
p {
background: var(--dark-three);
color: white;
text-shadow: 1px 1px 2px white;
padding: 5px 10px 5px 10px;
font-size: 25px;
border-radius: 7px;
margin-top: 10px;
transition: 0.4s;
}
</style>

View File

@ -1,12 +0,0 @@
// https://v2.nuxt.com/deployments/pm2/
module.exports = {
apps: [
{
name: "ngn13.fun website",
exec_mode: "cluster",
instances: "max",
script: "./node_modules/nuxt/bin/nuxt.js",
args: "start"
}
]
}

View File

@ -1,12 +0,0 @@
<template>
</template>
<script>
export default {
props: ["error"],
layout: "error",
mounted() {
this.$router.push({ path: "/" })
}
}
</script>

View File

@ -1,46 +0,0 @@
const express = require("express")
const { MongoClient } = require("mongodb")
const { makeID } = require("../api/util.js")
require("dotenv").config()
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
const client = new MongoClient(process.env.DATABASE)
app.get("/:id", async (req, res) => {
const id = req.params.id
if (typeof id !== "string") return res.redirect("/projects")
await client.connect()
const db = client.db("ngn13")
const col = db.collection("projects")
const projects = await col.find().toArray()
for (let i = 0; i < projects.length; i++) {
if (makeID(projects[i]["name"]) === id) {
res.redirect(projects[i]["url"])
await col.updateOne(
{ name: projects[i]["name"] },
{ $set: { click: projects[i]["click"] + 1 } }
)
}
}
return res.redirect("/projects")
})
async function pexit() {
await client.close()
process.exit()
}
process.on("SIGTERM", pexit)
process.on("SIGINT", pexit)
export default {
path: "/l",
handler: app
}

View File

@ -1,41 +0,0 @@
export default {
head: {
title: "[ngn]",
htmlAttrs: {
lang: "en"
},
meta: [
{ charset: "utf-8" },
{ name: "viewport", content: "width=1200" },
{ hid: "description", name: "description", content: "" },
{ name: "format-detection", content: "telephone=no" },
{ hid: "og:title", content: "[ngn]" },
{
hid: "og:description",
content:
"personal website of ngn | read my blogs, check out my projects, discover cool resources"
},
{ hid: "og:url", content: "https://ngn13.fun" },
{ name: "theme-color", content: "#141414", "data-react-helmet": "true" }
],
link: [
{
rel: "stylesheet",
href: "https://files.ngn13.fun/boxicons.min.css",
},
]
},
css: ["@/static/global.css"],
plugins: [],
components: true,
buildModules: [],
modules: ["@nuxtjs/axios"],
axios: {
baseURL: "/"
},
build: {},
serverMiddleware: {
"/api": "~/api",
"/l": "~/links"
}
}

27892
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,17 @@
{
"name": "my-website",
"version": "2.5.0",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"dependencies": {
"@nuxtjs/axios": "^5.13.6",
"core-js": "^3.25.3",
"dompurify": "^3.0.3",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"marked": "^5.0.3",
"mongodb": "^5.5.0",
"nuxt": "^2.15.8",
"vue": "^2.7.10",
"vue-server-renderer": "^2.7.10",
"vue-template-compiler": "^2.7.10"
}
"name": "website",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"svelte": "^4.0.5",
"vite": "^4.4.2"
},
"type": "module"
}

View File

@ -1,111 +0,0 @@
<template>
<div class="all">
<Navbar />
<Header>
<label class="glitch title">{{ post.title }}</label>
<p>{{ post.info }}</p>
</Header>
<div class="postcontain">
<main class="markdown-body" v-html="content"></main>
</div>
</div>
</template>
<script>
import Navbar from "../../../components/Navbar.vue"
import Header from "../../../components/Header.vue"
import axios from "axios"
import * as DOMPurify from "dompurify"
import marked from "marked"
export default {
head() {
return {
title: "[ngn] | blog",
meta: [
{
hid: "description",
name: "description",
content: "read my blog posts"
}
]
}
},
data() {
return {
post: {},
lang: "",
content: ""
}
},
async created() {
const res = await axios.get(`/api/blog/get?id=${this.$route.params.id}`)
if (res.data["error"] === 3) return this.$router.push({ path: "/blog" })
this.post = res.data["post"]
this.post["content"] = this.post["content"].replaceAll(
"\n<br>\n<br>\n",
"\n\n"
)
this.content = DOMPurify.sanitize(
marked.parse(this.post["content"], { breaks: true }),
{
ADD_TAGS: ["iframe"],
ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling"]
}
)
}
}
</script>
<style scoped>
glitch {
font-size: 80px;
}
p {
font-size: 30px;
}
.info {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.postcontain {
padding: 50px;
}
.markdown-body {
font-size: 25px;
padding: 50px;
border-radius: 10px;
background-color: var(--dark-two);
box-shadow: var(--def-shadow);
}
</style>
<style>
.markdown-body {
font-family: "Ubuntu", sans-serif;
}
.markdown-body h1 {
border-bottom: 1px solid #505050;
}
.markdown-body iframe {
display: block;
margin: 20px 0px;
}
.markdown-body a {
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
text-shadow: none;
}
</style>

View File

@ -1,92 +0,0 @@
<template>
<div>
<Navbar />
<Header> <label class="glitch">/dev/</label>blog </Header>
<div class="blogs">
<Input :keyup="keyup" placeholder="Search post" type="text" />
<PostPreview
v-for="post in posts"
:key="post.title"
:title="post.title"
:desc="post.desc"
:info="post.info"
:url="post.url"
>
{{ post.desc }}
</PostPreview>
</div>
<NewPost v-if="logged" />
</div>
</template>
<script>
import Navbar from "../../components/Navbar.vue"
import Header from "../../components/Header.vue"
import NewPost from "../../components/NewPost.vue"
import PostPreview from "../../components/PostPreview.vue"
import axios from "axios"
export default {
head() {
return {
title: "[ngn] | blog",
meta: [
{
hid: "description",
name: "description",
content: "read my blog posts"
}
]
}
},
data() {
return {
logged: false,
posts: [],
all: []
}
},
mounted: async function () {
if (localStorage.getItem("token")) this.logged = true
const res = await axios.get("/api/blog/sum")
let posts = []
res.data["posts"].forEach((post) => {
posts.push({
title: post.title,
desc: post.desc,
info: post.info,
url: `/blog/${post.title.toLowerCase().replaceAll(" ", "")}`
})
})
this.posts = posts
this.all = posts
},
methods: {
keyup(e) {
let val = e.target.value
// search looks at name and info
this.posts = []
for (let i = 0; i < this.all.length; i++) {
if (this.all[i].title.toLowerCase().includes(val.toLowerCase()))
this.posts.push(this.all[i])
else if (this.all[i].info.toLowerCase().includes(val.toLowerCase()))
this.posts.push(this.all[i])
}
}
}
}
</script>
<style scoped>
.blogs {
padding: 50px;
gap: 35px;
display: flex;
flex-direction: column;
gap: 30px;
align-items: center;
}
</style>

View File

@ -1,109 +0,0 @@
<template>
<div>
<Navbar />
<Header> <label class="glitch">echo</label> hello world! </Header>
<div class="info">
<Card>
<h1>👋 Welcome to my website!</h1>
<h2>
I am a high school student who is interested in
<br />
cyber security
<br />
coding
<br />
electronics
<br />
gaming
<br />
simply: everything about computers!
</h2>
</Card>
<Card>
<h1>👉 Contact me</h1>
<h2>You can contact me on the following platforms:</h2>
<a href="https://discord.com/users/568131907368386565"
><i class="bx bxl-discord-alt"></i> Discord</a
>
<br />
<a href="https://github.com/ngn13"
><i class="bx bxl-github"></i> Github</a
>
<br />
<a href="https://mastodon.social/@ngn"
><i class="bx bxl-mastodon"></i> Mastodon</a
>
<br />
<a href="mailto:ngn13proton@proton.me"
><i class="bx bxs-envelope"></i> Mail</a
>
<br />
<h2>or private message me on matrix:</h2>
<a><i>[matrix]</i> @ngn:matrix.ngn13.fun</a>
</Card>
</div>
<Logout v-if="logged" />
<div class="version">
<p>v2.6</p>
</div>
</div>
</template>
<script>
import Navbar from "../components/Navbar.vue"
import Header from "../components/Header.vue"
import Card from "../components/Card.vue"
import Logout from "../components/Logout.vue"
export default {
head() {
return {
title: "[ngn]",
meta: [
{
hid: "description",
name: "description",
content: "homepage of my website"
}
]
}
},
data() {
return {
logged: false
}
},
mounted() {
if (localStorage.getItem("token")) this.logged = true
}
}
</script>
<style scoped>
.info {
padding: 50px;
gap: 30px;
display: flex;
}
.version {
color: var(--dark-fife);
position: fixed;
bottom: 10px;
right: 10px;
font-size: 15px;
}
i {
font-style: normal;
}
@media only screen and (max-width: 1076px) {
.info {
flex-direction: column;
}
.info div {
width: auto;
}
}
</style>

View File

@ -1,56 +0,0 @@
<template>
<div>
<h1>Login Page</h1>
<Input
:keyup="function () {}"
placeholder="Password"
type="password"
id="pass"
/>
<Button :click="click">Login</Button>
</div>
</template>
<script>
import Input from "../components/Input.vue"
import Button from "../components/Button.vue"
import axios from "axios"
export default {
methods: {
async click(e) {
const pass = document.getElementById("pass").value
const res = await axios.get(`/api/auth/login?pass=${pass}`)
if (res.data["error"] === 0) {
localStorage.setItem("token", res.data["token"])
return (location.href = "/")
}
alert("Incorrect password!")
}
}
}
</script>
<style scoped>
div {
padding: 50px;
background: var(--dark-three);
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
display: flex;
flex-direction: column;
gap: 20px;
color: var(--white);
align-items: center;
justify-content: center;
}
h1 {
font-size: 70px;
margin-bottom: 20px;
}
</style>

View File

@ -1,105 +0,0 @@
<template>
<div>
<Navbar />
<Header> <label class="glitch">ls -la</label> projects </Header>
<div class="projects">
<ProjectList v-for="project in projects" :key="project.id">
<Project
v-if="logged"
v-for="p in project.list"
:key="p.name"
:name="`${p.name} (${p.click})`"
:desc="p.desc"
:url="p.url"
/>
<Project
v-if="!logged"
v-for="p in project.list"
:key="p.desc"
:name="p.name"
:desc="p.desc"
:url="p.url"
/>
</ProjectList>
</div>
<NewProject v-if="logged" />
</div>
</template>
<script>
import ProjectList from "../components/ProjectList.vue"
import Project from "../components/Project.vue"
import NewProject from "../components/NewProject.vue"
import axios from "axios"
export default {
head() {
return {
title: "[ngn] | projects",
meta: [
{
hid: "description",
name: "description",
content: "check out my projects"
}
]
}
},
data() {
return {
logged: false,
projects: []
}
},
mounted: async function () {
if (localStorage.getItem("token")) this.logged = true
const res = await axios.get("/api/projects/get")
let all = res.data["projects"]
let pcounter = 0
let projects = []
let project = {
id: pcounter,
list: []
}
for (let i = 0; i < all.length; i++) {
if (project["list"].length === 3) {
projects.push(project)
pcounter += 1
project = {
id: pcounter,
list: []
}
}
project["list"].push({
name: all[i]["name"],
desc: all[i]["desc"],
click: all[i]["click"],
url: `/l/${all[i]["name"].toLowerCase().replaceAll(" ", "")}`
})
if (i === all.length - 1) {
projects.push(project)
}
}
this.projects = projects
}
}
</script>
<style>
.projects {
padding: 50px;
display: flex;
flex-direction: column;
}
@media only screen and (max-width: 1121px) {
.projects {
padding: 50px;
}
}
</style>

View File

@ -1,108 +0,0 @@
<template>
<main>
<Navbar />
<Header> <label class="glitch">cat</label> {{ header }} </Header>
<div class="resources">
<Input :keyup="keyup" placeholder="Search resource" type="text" />
<Resource
v-for="res in show_resources"
:key="res.name"
:name="res.name"
:tags="res.tags"
:url="res.url"
/>
</div>
<NewResource v-if="logged" />
</main>
</template>
<script>
import axios from "axios"
import Resource from "../components/Resource.vue"
import Input from "../components/Input.vue"
import NewResource from "../components/NewResource.vue"
export default {
head() {
return {
title: "[ngn] | resources",
meta: [
{
hid: "description",
name: "description",
content: "discover new resources"
}
]
}
},
data() {
return {
header: "resources",
logged: false,
sum_resources: [],
all_resources: [],
show_resources: []
}
},
methods: {
keyup(e) {
let search = e.target.value
if (e.key === "Backspace" && search === "") {
this.header = "resources"
this.show_resources = this.sum_resources
return
}
if (e.key === "OS") return
this.header = `resources | grep ${search}`
// dirty asf search alg
this.show_resources = []
for (let i = 0; i < this.all_resources.length; i++) {
if (
this.all_resources[i].name
.toLowerCase()
.includes(search.toLowerCase())
) {
this.show_resources.push(this.all_resources[i])
continue
}
for (let e = 0; e < this.all_resources[i].tags.length; e++) {
if (
this.all_resources[i].tags[e]
.toLowerCase()
.includes(search.toLowerCase())
) {
this.show_resources.push(this.all_resources[i])
break
}
}
}
}
},
mounted: async function () {
if (localStorage.getItem("token")) this.logged = true
// request top 10 resources so we can
// render the DOM as fast as possible
let res = await axios.get("/api/resources/get?sum=1")
this.sum_resources = res.data["resources"]
this.show_resources = this.sum_resources
// then we can load all the resources
res = await axios.get("/api/resources/get")
this.all_resources = res.data["resources"]
}
}
</script>
<style scoped>
.resources {
padding: 50px;
padding-bottom: 60px;
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
}
</style>

11
src/app.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

52
src/lib/card.svelte Normal file
View File

@ -0,0 +1,52 @@
<script>
export let title
let current = ""
let i = 0
while (title.length > i) {
let c = title[i]
setTimeout(()=>{
current += c
}, 100*(i+1))
i += 1
}
</script>
<div class="main">
<div class="title">
root@ngn13.fun:~# {current}
</div>
<div class="content">
<slot></slot>
</div>
</div>
<style>
.main {
display: flex;
flex-direction: column;
width: 100%;
background: var(--dark-three);
box-shadow: var(--box-shadow);
border-radius: 7px;
}
.title {
background: var(--dark-two);
padding: 30px;
border-radius: 7px 7px 0px 0px;
font-size: 20px;
font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
color: white;
}
.content {
background: var(--dark-three);
padding: 40px;
padding-top: 30px;
color: white;
border-radius: 5px;
font-size: 25px;
}
</style>

29
src/lib/header.svelte Normal file
View File

@ -0,0 +1,29 @@
<script></script>
<header>
<h1>
<slot></slot>
</h1>
</header>
<style>
header {
background:
linear-gradient(rgba(1, 1, 1, 0.96),
rgba(11, 11, 11, 0.808)),
url("https://files.ngn13.fun/banner.png");
background-size: 50%;
width: 100%;
height: 100%;
}
h1 {
font-weight: 900;
font-size: 5.5vw;
padding: 120px;
text-align: center;
color: white;
text-shadow: var(--text-shadow);
text-size-adjust: 80%;
}
</style>

51
src/lib/navbar.svelte Normal file
View File

@ -0,0 +1,51 @@
<script>
import NavbarLink from "./navbar_link.svelte";
</script>
<nav>
<div>
<h3>[ngn]</h3>
</div>
<div>
<NavbarLink link="/">home</NavbarLink>
<NavbarLink link="/projects">projects</NavbarLink>
<NavbarLink link="/resources">resources</NavbarLink>
<NavbarLink link="/blog">blog</NavbarLink>
<NavbarLink link="https://github.com/ngn13/ngn13.fun">source</NavbarLink>
</div>
</nav>
<style>
nav {
background: var(--dark-one);
padding: 25px 30px 27px 25px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
border-bottom: solid 1.5px black;
animation-name: borderAnimation;
animation-duration: 10s;
animation-iteration-count: infinite;
box-shadow: var(--def-shadow);
}
div {
display: flex;
overflow: hidden;
align-items: center;
justify-content: center;
gap: 1px;
}
h3 {
font-weight: 900;
font-size: 25px;
color: red;
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
}
</style>

View File

@ -0,0 +1,27 @@
<script>
import { page } from "$app/stores"
export let link
</script>
<div>
<a href="{link}"><slot></slot></a>
</div>
<style>
a {
margin-left: 20px;
font-weight: 700;
font-size: 22px;
text-decoration: none;
color: white;
cursor: pointer;
}
a:hover {
text-decoration: underline;
animation-name: underlineAnimation;
animation-duration: 5s;
animation-iteration-count: infinite;
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
}
</style>

12
src/routes/+layout.svelte Normal file
View File

@ -0,0 +1,12 @@
<script>
import Navbar from "../lib/navbar.svelte";
</script>
<main>
<Navbar />
<slot></slot>
</main>
<style>
@import "../../static/global.css";
</style>

63
src/routes/+page.svelte Normal file
View File

@ -0,0 +1,63 @@
<script>
import Header from "../lib/header.svelte";
import Card from "../lib/card.svelte";
</script>
<svelte:head>
<title>[ngn] | homepage</title>
<meta content="[ngn] | Homepage" property="og:title" />
<meta content="Homepage of my personal website" property="og:description" />
<meta content="https://ngn13.fun" property="og:url" />
<meta content="#141414" data-react-helmet="true" name="theme-color" />
</svelte:head>
<Header>
<c>echo</c>
hello world!
</Header>
<div class="flexbox">
<Card title="whoami">
👋 Hello! I'm ngn!
<ul>
<li>🇹🇷 I'm a high school student from Turkey</li>
<li>🖥️ I'm interested in cyber security, programming and electronics</li>
<li>❤️ I love and support Free/Libre and Open Source Software (FLOSS)</li>
<li>🐧 My GNU/Linux distribution of choice is Artix</li>
<li>😋 In my free time, I like playing Minecraft</li>
</ul>
</Card>
<Card title="pwd">
You are currently on my personal website, for all you nerds, here is some
techinal details you may want to know:
<ul>
<li><c></c> I built the frontend app using SvelteKit
<li><c></c> I deploy my app to vecel using Github actions</li>
<li><c>󰒋 </c> Backend server is written in Go and it's hosted on my server</li>
<li><c></c> And yup, I also have other services hosted on it</li>
</ul>
</Card>
</div>
<style>
.flexbox {
padding: 50px;
gap: 30px;
display: flex;
}
ul {
padding-left: 30px;
}
li {
padding-top: 15px;
}
@media only screen and (max-width: 1076px) {
.flexbox {
flex-direction: column;
}
}
</style>

View File

@ -0,0 +1,17 @@
<script>
import Header from "../../lib/header.svelte";
</script>
<svelte:head>
<title>[ngn] | projects</title>
<meta content="[ngn] | Projects" property="og:title" />
<meta content="Projects that I work on" property="og:description" />
<meta content="https://ngn13.fun" property="og:url" />
<meta content="#141414" data-react-helmet="true" name="theme-color" />
</svelte:head>
<Header><glitch>ls -l</glitch> projects</Header>
<style></style>

View File

@ -1,64 +1,13 @@
/*
* this what you would get from google fonts, i downloaded all the fonts and
* placed them in static/fonts because google fonts made my website load
* slower lol
*
* you can get the original css at:
* https://fonts.googleapis.com/css2?family=Ubuntu:wght@300&display=swap
* fonts are located under /static/fonts, they are from nerdfonts
* see nerdfonts.com
*
*/
/* cyrillic-ext */
@font-face {
font-family: 'Ubuntu';
font-family: "Ubuntu";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(./fonts/cyrillic-ext.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
src: url("/fonts/UbuntuNerdFont-Regular.ttf");
}
/* cyrillic */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(./fonts/cyrillic.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(./fonts/greek-ext.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(./fonts/greek.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* latin-ext */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(./fonts/latin-ext.woff2) format('woff2');
unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(./fonts/latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -666,7 +666,7 @@
.markdown-body span.float-left span {
margin: 13px 0 0;
}
https://github.com/ngn13/ngn13.fun/raw/main/static/fonts/latin.woff2
.markdown-body span.float-right {
display: block;
float: right;

View File

@ -1,12 +1,12 @@
@import url("./font.css");
@import url("./github.css");
@import "./font.css";
@import "./github.css";
:root {
--white: white;
--dark-one: #141414;
--dark-two: #18191a;
--dark-three: #282828;
--dark-four: #242526;
--dark-one: black;
--dark-two: #050505;
--dark-three: #121212;
--dark-four: #101010;
--dark-fife: #3a3b3c;
--border-rad: 30px;
/*
@ -15,7 +15,8 @@
rgba(0, 0, 0, 0.12) 0px -12px 30px, rgba(0, 0, 0, 0.12) 0px 4px 6px,
rgba(0, 0, 0, 0.17) 0px 12px 13px, rgba(0, 0, 0, 0.09) 0px -3px 5px;
*/
--def-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
--text-shadow: 0px 10px 20px rgba(90, 90, 90, 0.8);
--box-shadow: rgba(20, 20, 20, 0.19) 0px 10px 20px, rgba(30, 30, 30, 0.23) 0px 6px 6px;
}
* {
@ -30,7 +31,7 @@ body {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: #141414;
background: var(--dark-one);
font-family: "Ubuntu", sans-serif;
overflow-x: hidden;
}
@ -295,9 +296,8 @@ body {
}
}
.glitch {
c {
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
text-shadow: none;
}

13
svelte.config.js Normal file
View File

@ -0,0 +1,13 @@
import adapter from '@sveltejs/adapter-auto';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;

6
vite.config.js Normal file
View File

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});