ready to go

This commit is contained in:
ngn 2023-08-21 08:23:11 +03:00
parent 195e4c7e02
commit c76a8a5f56
21 changed files with 660 additions and 75 deletions

View File

@ -1,38 +1,20 @@
# create-svelte # [ngn13.fun](https://ngn13.fun) | my personal website
This is the frontend application for my personal website, it's written in SvelteKit and vanilla CSS
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!
```bash
# 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:
## development setup
```bash ```bash
git clone https://github.com/ngn13/ngn13.fun && cd ngn13.fun
npm i
npm run dev npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
``` ```
## Building ## build setup
To create a production version of your app:
```bash ```bash
git clone https://github.com/ngn13/ngn13.fun && cd ngn13.fun
npm i
npm run build npm run build
``` ```
You can preview the production build with `npm run preview`. ## license
you cannot publish my website or parts of it on any server/domain without my permission
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. if you want to do this (for some reason) [contact me](mailto:ngn13proton@proton.me)

57
package-lock.json generated
View File

@ -7,6 +7,11 @@
"": { "": {
"name": "website", "name": "website",
"version": "0.0.1", "version": "0.0.1",
"dependencies": {
"@types/dompurify": "^3.0.2",
"dompurify": "^3.0.5",
"marked": "^7.0.4"
},
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4", "@sveltejs/kit": "^1.20.4",
@ -527,12 +532,25 @@
"integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==",
"dev": true "dev": true
}, },
"node_modules/@types/dompurify": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.2.tgz",
"integrity": "sha512-YBL4ziFebbbfQfH5mlC+QTJsvh0oJUrWbmxKMyEdL7emlHJqGR2Qb34TEFKj+VCayBvjKy3xczMFNhugThUsfQ==",
"dependencies": {
"@types/trusted-types": "*"
}
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
"dev": true "dev": true
}, },
"node_modules/@types/trusted-types": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz",
"integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g=="
},
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.10.0", "version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
@ -651,6 +669,11 @@
"integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==",
"dev": true "dev": true
}, },
"node_modules/dompurify": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz",
"integrity": "sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A=="
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.18.17", "version": "0.18.17",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz",
@ -763,6 +786,17 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/marked": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/marked/-/marked-7.0.4.tgz",
"integrity": "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 16"
}
},
"node_modules/mdn-data": { "node_modules/mdn-data": {
"version": "2.0.30", "version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
@ -1338,12 +1372,25 @@
"integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==",
"dev": true "dev": true
}, },
"@types/dompurify": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.2.tgz",
"integrity": "sha512-YBL4ziFebbbfQfH5mlC+QTJsvh0oJUrWbmxKMyEdL7emlHJqGR2Qb34TEFKj+VCayBvjKy3xczMFNhugThUsfQ==",
"requires": {
"@types/trusted-types": "*"
}
},
"@types/estree": { "@types/estree": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
"dev": true "dev": true
}, },
"@types/trusted-types": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz",
"integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g=="
},
"acorn": { "acorn": {
"version": "8.10.0", "version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
@ -1433,6 +1480,11 @@
"integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==",
"dev": true "dev": true
}, },
"dompurify": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz",
"integrity": "sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A=="
},
"esbuild": { "esbuild": {
"version": "0.18.17", "version": "0.18.17",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz",
@ -1521,6 +1573,11 @@
"@jridgewell/sourcemap-codec": "^1.4.15" "@jridgewell/sourcemap-codec": "^1.4.15"
} }
}, },
"marked": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/marked/-/marked-7.0.4.tgz",
"integrity": "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ=="
},
"mdn-data": { "mdn-data": {
"version": "2.0.30", "version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",

View File

@ -13,5 +13,10 @@
"svelte": "^4.0.5", "svelte": "^4.0.5",
"vite": "^4.4.2" "vite": "^4.4.2"
}, },
"type": "module" "type": "module",
"dependencies": {
"@types/dompurify": "^3.0.2",
"dompurify": "^3.0.5",
"marked": "^7.0.4"
}
} }

View File

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=1024">
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">

67
src/lib/card_link.svelte Normal file
View File

@ -0,0 +1,67 @@
<script>
export let title
export let url
let audio
let current = ""
let i = 0
while (title.length > i) {
let c = title[i]
setTimeout(()=>{
current += c
}, 100*(i+1))
i += 1
}
function epicSound() {
audio.play()
}
</script>
<a on:click={epicSound} data-sveltekit-preload-data href={url}>
<audio bind:this={audio} preload="auto">
<source src="/click.wav" type="audio/mpeg" />
</audio>
<div class="title">
{current}
</div>
<div class="content">
<slot></slot>
</div>
</a>
<style>
a {
display: flex;
flex-direction: column;
width: 100%;
background: var(--dark-three);
border-radius: 7px;
cursor: pointer;
transition: .4s;
text-decoration: none;
}
a:hover {
box-shadow: var(--box-shadow);
}
.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>

View File

@ -9,8 +9,7 @@
<style> <style>
header { header {
background: background:
linear-gradient(rgba(1, 1, 1, 0.96), linear-gradient(rgba(11, 11, 11, 0.808), rgba(1, 1, 1, 0.96)),
rgba(11, 11, 11, 0.808)),
url("https://files.ngn13.fun/banner.png"); url("https://files.ngn13.fun/banner.png");
background-size: 50%; background-size: 50%;
width: 100%; width: 100%;

View File

@ -10,7 +10,6 @@
<div> <div>
<NavbarLink link="/">home</NavbarLink> <NavbarLink link="/">home</NavbarLink>
<NavbarLink link="/projects">projects</NavbarLink> <NavbarLink link="/projects">projects</NavbarLink>
<NavbarLink link="/resources">resources</NavbarLink>
<NavbarLink link="/blog">blog</NavbarLink> <NavbarLink link="/blog">blog</NavbarLink>
<NavbarLink link="https://github.com/ngn13/ngn13.fun">source</NavbarLink> <NavbarLink link="https://github.com/ngn13/ngn13.fun">source</NavbarLink>
</div> </div>

View File

@ -1,10 +1,18 @@
<script> <script>
import { page } from "$app/stores" import { page } from "$app/stores"
export let link export let link
let audio
function epicSound() {
audio.play()
}
</script> </script>
<div> <div>
<a href="{link}"><slot></slot></a> <audio bind:this={audio} preload="auto">
<source src="/click.wav" type="audio/mpeg" />
</audio>
<a data-sveltekit-preload-data on:click={epicSound} href="{link}"><slot></slot></a>
</div> </div>
<style> <style>
@ -19,9 +27,9 @@ a {
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
animation-name: underlineAnimation; animation-name: underlineAnimation;
animation-duration: 5s; animation-duration: 5s;
animation-iteration-count: infinite; animation-iteration-count: infinite;
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
} }
</style> </style>

57
src/lib/project.svelte Normal file
View File

@ -0,0 +1,57 @@
<script>
import { goto } from "$app/navigation";
export let desc
export let url
let audio
function redirect() {
audio.play()
goto(url);
}
</script>
<main on:click={redirect}>
<audio bind:this={audio} preload="auto">
<source src="/click.wav" type="audio/mpeg" />
</audio>
<h1 class="c"></h1>
<div>
<h1><slot></slot></h1>
<p>{desc}</p>
</div>
</main>
<style>
main {
display: flex;
padding: 40px 60px 40px 60px;
background: var(--dark-two);
border-radius: 7px 7px 0px 0px;
justify-content: center;
align-content: center;
flex-direction: row;
cursor: pointer;
transition: .4s;
border: none;
color: white;
gap: 20px;
}
main:hover {
box-shadow: var(--box-shadow);
}
h1 {
font-size: 70px;
}
div h1 {
font-size: 30px;
}
div p {
margin-top: 10px;
font-size: 20px;
}
</style>

8
src/routes/+error.svelte Normal file
View File

@ -0,0 +1,8 @@
<script>
import { onMount } from "svelte"
import { goto } from "$app/navigation"
onMount(()=>{
goto("/")
})
</script>

View File

@ -5,10 +5,10 @@
<svelte:head> <svelte:head>
<title>[ngn] | homepage</title> <title>[ngn] | homepage</title>
<meta content="[ngn] | Homepage" property="og:title" /> <meta content="[ngn] | homepage" property="og:title" />
<meta content="Homepage of my personal website" property="og:description" /> <meta content="Homepage of my personal website" property="og:description" />
<meta content="https://ngn13.fun" property="og:url" /> <meta content="https://ngn13.fun" property="og:url" />
<meta content="#141414" data-react-helmet="true" name="theme-color" /> <meta content="#000000" data-react-helmet="true" name="theme-color" />
</svelte:head> </svelte:head>
<Header> <Header>
@ -16,6 +16,7 @@
hello world! hello world!
</Header> </Header>
<main>
<div class="flexbox"> <div class="flexbox">
<Card title="whoami"> <Card title="whoami">
👋 Hello! I'm ngn! 👋 Hello! I'm ngn!
@ -32,29 +33,84 @@
You are currently on my personal website, for all you nerds, here is some You are currently on my personal website, for all you nerds, here is some
techinal details you may want to know: techinal details you may want to know:
<ul> <ul>
<li><c></c> I built the frontend app using SvelteKit <li><c></c> I built the frontend app using SvelteKit</li>
<li><c></c> I deploy my app to vecel using Github actions</li> <li><c></c> I deploy my app to vercel using Github actions</li>
<li><c>󰒋 </c> Backend server is written in Go and it's hosted on my server</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> <li><c></c> And yup, I also have other services hosted on the same server</li>
</ul> </ul>
</Card> </Card>
</div> </div>
<div class="flexbox">
<Card title="ps -eaf">
I usually spend my time...
<ul>
<li><c></c> building random projects</li>
<li><c>󰓂 </c> contributing stuff that I like</li>
<li><c>󰈻</c> solving CTFs</li>
<li><c>󰌢 </c> customizing my desktop</li>
<li><c>󱀉 </c> posting random stuff on my blog, which you should definitely check out (it's very active)</li>
</ul>
</Card>
<Card title="wall">
If you want to have a chat, you can find me on the following platforms:
<ul>
<li><c></c> <a href="https://github.com/ngn13">Github</a></li>
<li><c>󰫑 </c> <a href="https://mastodon.social/@ngn">Mastodon</a></li>
<li><c>󰙯 </c> <a href="https://discord.com/users/568131907368386565">Discord</a></li>
<li><c></c> <a href="mailto:ngn13proton@proton.me">Email</a></li>
</ul>
Or you can DM me on matrix:
<br>
<c>@ngn:matrix.ngn13.fun</c>
</Card>
</div>
</main>
<div class="version">
<p>v3.0</p>
</div>
<style> <style>
.flexbox { main{
padding: 50px;
gap: 30px;
display: flex; display: flex;
flex-direction: column;
gap: 35px;
padding: 50px;
}
.flexbox {
display: flex;
gap: 30px;
} }
ul { ul {
padding-left: 30px; padding-left: 30px;
margin-bottom: 20px;
} }
li { li {
padding-top: 15px; padding-top: 15px;
} }
a {
color: white;
text-decoration: none;
}
a:hover {
font-weight: 900;
}
.version {
color: var(--dark-fife);
position: fixed;
bottom: 10px;
right: 10px;
font-size: 15px;
}
@media only screen and (max-width: 1076px) { @media only screen and (max-width: 1076px) {
.flexbox { .flexbox {
flex-direction: column; flex-direction: column;

9
src/routes/blog/+page.js Normal file
View File

@ -0,0 +1,9 @@
export async function load({ fetch }) {
const api = import.meta.env.VITE_API_URL_DEV
const res = await fetch(api+"/blog/sum")
const data = await res.json()
return {
posts: data["result"]
}
}

View File

@ -0,0 +1,87 @@
<script>
import Header from "../../lib/header.svelte";
import CardLink from "../../lib/card_link.svelte";
import { onMount } from "svelte";
export let data
let inpt
let all = data.posts
let posts = all
let inputcls = "c"
function show(term){
posts = []
for(let i = 0; i < all.length; i++) {
if (all[i].title.toLowerCase().includes(term.toLowerCase())){
posts.push(all[i])
}
}
if (posts.length == 0){
inputcls = "nf"
return
}
inputcls = "c"
}
onMount(() => {
inpt.focus()
show(inpt.value)
})
function search(){
let term = inpt.value
show(term)
}
</script>
<svelte:head>
<title>[ngn] | blog</title>
<meta content="[ngn] | blog" property="og:title" />
<meta content="View my blog posts" property="og:description" />
<meta content="https://ngn13.fun" property="og:url" />
<meta content="#000000" data-react-helmet="true" name="theme-color" />
</svelte:head>
<Header>
<c>/dev/</c>blog
</Header>
<main>
<input on:keyup={search} bind:this={inpt} class="{inputcls}" placeholder="Search for a post">
{#each posts as post}
<CardLink url="/blog/{post.id}" title="{post.title}">
<p>{post.author} | {post.date}</p>
<br>
{post.content}...
</CardLink>
{/each}
</main>
<style>
main{
display: flex;
flex-direction: column;
gap: 35px;
padding: 15%;
padding-top: 50px;
}
input {
text-align: center;
background: var(--dark-two);
background: none;
border: none;
outline: none;
font-size: 40px;
}
p {
font-size: 20px;
}
.nf {
color: rgb(120, 120, 120);
}
</style>

View File

@ -0,0 +1,14 @@
export async function load({ fetch, params }) {
const id = params.id
const api = import.meta.env.VITE_API_URL_DEV
const res = await fetch(api+"/blog/get?id="+id)
const data = await res.json()
if (data["error"] != "") {
return {
error: data["error"]
}
}
return data["result"]
}

View File

@ -0,0 +1,163 @@
<script>
import Header from "../../../lib/header.svelte"
import { goto } from "$app/navigation"
import { onMount } from "svelte"
import DOMPurify from "dompurify"
import { marked } from "marked"
export let data
let sanitized
const api = import.meta.env.VITE_API_URL_DEV
let upvote_status = "inactive"
let downvote_status = "inactive"
let voted = false
let audio
async function get_status() {
const res = await fetch(api+"/blog/vote/status?id="+data.id)
const json = await res.json()
if(json["error"]!= ""){
return
}
if (json["result"] == "upvote") {
upvote_status = "active"
downvote_status = "inactive"
}
else {
downvote_status = "active"
upvote_status = "inactive"
}
voted = true
}
onMount(async ()=>{
if (data.title == undefined)
goto("/blog")
sanitized = DOMPurify.sanitize(
marked.parse(data.content, { breaks: true }),
{
ADD_TAGS: ["iframe"],
ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling"]
}
)
await get_status()
})
async function upvote(){
audio.play()
const res = await fetch(api+"/blog/vote/set?id="+data.id+"&to=upvote")
const json = await res.json()
if(json["error"] != ""){
return
}
if (voted){
data.vote += 2
}
else {
voted = true
data.vote += 1
}
await get_status()
}
async function downvote(){
audio.play()
const res = await fetch(api+"/blog/vote/set?id="+data.id+"&to=downvote")
const json = await res.json()
if(json["error"] != ""){
return
}
if (voted){
data.vote -= 2
}
else {
voted = true
data.vote -= 1
}
await get_status()
}
</script>
<svelte:head>
<title>[ngn] | blog</title>
<meta content="[ngn] | blog" property="og:title" />
<meta content="View my blog posts" property="og:description" />
<meta content="https://ngn13.fun" property="og:url" />
<meta content="#000000" data-react-helmet="true" name="theme-color" />
</svelte:head>
<Header>
<c>{data.title}</c>
<p>{data.author} | {data.date}</p>
</Header>
<main>
<audio bind:this={audio} preload="auto">
<source src="/click.wav" type="audio/mpeg" />
</audio>
<div class="content markdown-body">
{@html sanitized}
</div>
<div class="votes">
<h3 on:click={async ()=>{upvote()}} class="{upvote_status}">󰜷</h3>
<p>{data.vote}</p>
<h3 on:click={async ()=>{downvote()}} class="{downvote_status}">󰜮</h3>
</div>
</main>
<style>
p {
font-size: 30px;
}
main {
padding: 50px;
color: white;
display: flex;
flex-direction: row;
gap: 20px;
}
.content {
padding: 30px;
background: var(--dark-two);
box-shadow: var(--box-shadow);
border-radius: 7px;
}
.votes {
display: flex;
flex-direction: column;
text-align: center;
text-shadow: var(--text-shadow);
}
.votes h3{
font-size: 40px;
cursor: pointer;
}
.votes h3:hover {
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
}
.active {
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
}
</style>

View File

@ -0,0 +1,35 @@
export async function load({ fetch }) {
const api = import.meta.env.VITE_API_URL_DEV
const res = await fetch(api+"/projects/get")
const data = await res.json()
if (data["error"] != ""){
return {
error: data["error"]
}
}
let all = data["result"]
let counter = 0
let currentlist = []
let projects = []
for (let i = 0; i < all.length; i++){
currentlist.push(all[i])
counter += 1
if(i == all.length-1 && counter != 3){
projects.push(currentlist)
}
if (counter == 3) {
projects.push(currentlist)
currentlist = []
counter = 0
}
}
return {
projects
}
}

View File

@ -1,17 +1,50 @@
<script> <script>
import Header from "../../lib/header.svelte"; import Header from "../../lib/header.svelte";
</script> import Project from "../../lib/project.svelte";
export let data
console.log(data)
</script>
<svelte:head> <svelte:head>
<title>[ngn] | projects</title> <title>[ngn] | projects</title>
<meta content="[ngn] | Projects" property="og:title" /> <meta content="[ngn] | projects" property="og:title" />
<meta content="Projects that I work on" property="og:description" /> <meta content="Projects that I work on" property="og:description" />
<meta content="https://ngn13.fun" property="og:url" /> <meta content="https://ngn13.fun" property="og:url" />
<meta content="#141414" data-react-helmet="true" name="theme-color" /> <meta content="#000000" data-react-helmet="true" name="theme-color" />
</svelte:head> </svelte:head>
<Header><glitch>ls -l</glitch> projects</Header> <Header><c>ls -l</c> projects</Header>
<main>
{#each data.projects as projectlist}
<div class="flexrow">
{#each projectlist as project}
<Project url="{project.link}" desc="{project.desc}">{project.name}</Project>
{/each}
</div>
{/each}
</main>
<style>
main {
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
padding: 50px;
gap: 25px;
}
.flexrow {
display: flex;
flex-direction: row;
align-content: center;
justify-content: center;
gap: 25px;
}
<style></style> @media only screen and (max-width: 1316px) {
.flexrow {
flex-direction: column;
}
}
</style>

BIN
static/click.wav Normal file

Binary file not shown.

View File

@ -47,6 +47,9 @@
} }
.markdown-body a { .markdown-body a {
animation-name: colorAnimation;
animation-iteration-count: infinite;
animation-duration: 10s;
background-color: transparent; background-color: transparent;
color: #58a6ff; color: #58a6ff;
text-decoration: none; text-decoration: none;

View File

@ -25,17 +25,15 @@
} }
body { body {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: var(--dark-one); background: var(--dark-one);
font-family: "Ubuntu", sans-serif; font-family: "Ubuntu", sans-serif;
overflow-x: hidden; overflow-x: hidden;
} }
::selection {
background: rgba(0, 0, 0, 0.7);
}
::-webkit-scrollbar { ::-webkit-scrollbar {
border-radius: 10px; border-radius: 10px;
width: 10px; width: 10px;
@ -296,7 +294,7 @@ body {
} }
} }
c { .c, c {
animation-name: colorAnimation; animation-name: colorAnimation;
animation-iteration-count: infinite; animation-iteration-count: infinite;
animation-duration: 10s; animation-duration: 10s;

View File

@ -7,7 +7,12 @@ const config = {
// If your environment is not supported or you settled on a specific environment, switch out the adapter. // 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. // See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter() adapter: adapter()
} },
onwarn: (warning, handler) => {
if (warning.code === "a11y-click-events-have-key-events") return
handler(warning)
},
}; };
export default config; export default config;