update?
This commit is contained in:
10
app/.gitignore
vendored
Normal file
10
app/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
2
app/.npmrc
Normal file
2
app/.npmrc
Normal file
@ -0,0 +1,2 @@
|
||||
engine-strict=true
|
||||
resolution-mode=highest
|
10
app/Dockerfile
Normal file
10
app/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM node:20-alpine3.17 as build
|
||||
|
||||
RUN apk update && apk upgrade && adduser -D svelte
|
||||
USER svelte
|
||||
|
||||
WORKDIR /app
|
||||
COPY --chown=svelteuser:svelte . /app
|
||||
|
||||
RUN npm install && npm run build
|
||||
CMD ["npm", "run", "preview"]
|
20
app/README.md
Normal file
20
app/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# [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
|
||||
|
||||
## development setup
|
||||
```bash
|
||||
git clone https://github.com/ngn13/ngn13.fun && cd ngn13.fun
|
||||
npm i
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## build setup
|
||||
```bash
|
||||
git clone https://github.com/ngn13/ngn13.fun && cd ngn13.fun
|
||||
npm i
|
||||
npm run build
|
||||
```
|
||||
|
||||
## license
|
||||
you cannot publish my website or parts of it on any server/domain without my permission
|
||||
if you want to do this (for some reason) [contact me](mailto:ngn13proton@proton.me)
|
1762
app/package-lock.json
generated
Normal file
1762
app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
app/package.json
Normal file
22
app/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "website",
|
||||
"version": "4.0.0",
|
||||
"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",
|
||||
"dependencies": {
|
||||
"@types/dompurify": "^3.0.2",
|
||||
"dompurify": "^3.0.5",
|
||||
"marked": "^7.0.4"
|
||||
}
|
||||
}
|
11
app/src/app.html
Normal file
11
app/src/app.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=1024">
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
52
app/src/lib/card.svelte
Normal file
52
app/src/lib/card.svelte
Normal 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>
|
69
app/src/lib/card_link.svelte
Normal file
69
app/src/lib/card_link.svelte
Normal file
@ -0,0 +1,69 @@
|
||||
<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);
|
||||
box-shadow: var(--box-shadow);
|
||||
border-radius: 7px;
|
||||
cursor: pointer;
|
||||
transition: .4s;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover > .title {
|
||||
text-shadow: var(--text-shadow);
|
||||
}
|
||||
|
||||
.title {
|
||||
border: solid 1px var(--dark-two);
|
||||
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>
|
28
app/src/lib/header.svelte
Normal file
28
app/src/lib/header.svelte
Normal file
@ -0,0 +1,28 @@
|
||||
<script></script>
|
||||
|
||||
<header>
|
||||
<h1>
|
||||
<slot></slot>
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
header {
|
||||
background:
|
||||
linear-gradient(rgba(11, 11, 11, 0.808), rgba(1, 1, 1, 0.96)),
|
||||
url("https://files.ngn.tf/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>
|
50
app/src/lib/navbar.svelte
Normal file
50
app/src/lib/navbar.svelte
Normal file
@ -0,0 +1,50 @@
|
||||
<script>
|
||||
import NavbarLink from "./navbar_link.svelte";
|
||||
</script>
|
||||
|
||||
<nav>
|
||||
<div>
|
||||
<h3>[ngn]</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<NavbarLink link="/">home</NavbarLink>
|
||||
<NavbarLink link="/services">services</NavbarLink>
|
||||
<NavbarLink link="/blog">blog</NavbarLink>
|
||||
<NavbarLink type="icon" link="https://github.com/ngn13/website"></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>
|
||||
|
48
app/src/lib/navbar_link.svelte
Normal file
48
app/src/lib/navbar_link.svelte
Normal file
@ -0,0 +1,48 @@
|
||||
<script>
|
||||
import { page } from "$app/stores"
|
||||
export let link
|
||||
export let type
|
||||
let audio
|
||||
|
||||
function epicSound() {
|
||||
audio.play()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<audio bind:this={audio} preload="auto">
|
||||
<source src="/click.wav" type="audio/mpeg" />
|
||||
</audio>
|
||||
{#if type==="icon"}
|
||||
<a class="icon" data-sveltekit-preload-data on:click={epicSound} href="{link}"><slot></slot></a>
|
||||
{:else}
|
||||
<a data-sveltekit-preload-data on:click={epicSound} href="{link}"><slot></slot></a>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
a {
|
||||
margin-left: 20px;
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
|
||||
animation-name: underlineAnimation;
|
||||
animation-duration: 5s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.icon:hover {
|
||||
text-decoration: none;
|
||||
text-shadow: 3px 4px 7px rgba(81, 67, 21, 0.8);
|
||||
animation-name: colorAnimation;
|
||||
animation-duration: 5s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
</style>
|
73
app/src/lib/service.svelte
Normal file
73
app/src/lib/service.svelte
Normal file
@ -0,0 +1,73 @@
|
||||
<script>
|
||||
export let desc
|
||||
export let url
|
||||
|
||||
let icon = ""
|
||||
let audio
|
||||
|
||||
function copy() {
|
||||
audio.play()
|
||||
navigator.clipboard.writeText(url)
|
||||
icon = ""
|
||||
setTimeout(()=>{
|
||||
icon = ""
|
||||
}, 500)
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<audio bind:this={audio} preload="auto">
|
||||
<source src="/click.wav" type="audio/mpeg" />
|
||||
</audio>
|
||||
<div>
|
||||
<h1><slot></slot></h1>
|
||||
<p>{desc}</p>
|
||||
</div>
|
||||
<div>
|
||||
<a on:click={copy} href="#">{icon}</a>
|
||||
<a href="{url}"></a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 30px 30px 30px 30px;
|
||||
background: var(--dark-two);
|
||||
border-radius: 7px 7px 0px 0px;
|
||||
box-shadow: var(--box-shadow);
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border: none;
|
||||
color: white;
|
||||
gap: 100px;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
div h1 {
|
||||
animation-name: colorAnimation;
|
||||
animation-duration: 10s;
|
||||
animation-iteration-count: infinite;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
div p {
|
||||
margin-top: 10px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-align: center;
|
||||
font-size: 30px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
animation-name: colorAnimation;
|
||||
animation-duration: 5s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
</style>
|
8
app/src/routes/+error.svelte
Normal file
8
app/src/routes/+error.svelte
Normal file
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { goto } from "$app/navigation"
|
||||
|
||||
onMount(()=>{
|
||||
goto("/")
|
||||
})
|
||||
</script>
|
12
app/src/routes/+layout.svelte
Normal file
12
app/src/routes/+layout.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import Navbar from "../lib/navbar.svelte";
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<Navbar />
|
||||
<slot></slot>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
@import "../../static/global.css";
|
||||
</style>
|
139
app/src/routes/+page.svelte
Normal file
139
app/src/routes/+page.svelte
Normal file
@ -0,0 +1,139 @@
|
||||
<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="#000000" data-react-helmet="true" name="theme-color" />
|
||||
</svelte:head>
|
||||
|
||||
<Header>
|
||||
<c>echo</c>
|
||||
hello world!
|
||||
</Header>
|
||||
|
||||
<main>
|
||||
<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, however I am currently running Arch</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>
|
||||
<li><c> </c> Backend API is written in Go and it's hosted on my server</li>
|
||||
<li><c> </c> All assets (images, fonts etc.) are hosted on my server as well</li>
|
||||
<li><c> </c> No cloudflare, no CAPTCHAs, no CDNs, this website is %100 privacy friendly</li>
|
||||
</ul>
|
||||
</Card>
|
||||
</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, you should definitely check it out btw (it's very active)</li>
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
<Card title="wall">
|
||||
Here are some of my socials:
|
||||
<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>
|
||||
</ul>
|
||||
If you want to contact me directly, send me an email:
|
||||
<ul>
|
||||
<li><c></c> <a href="mailto:ngn13proton@proton.me">Personal email address</a></li>
|
||||
<li><c></c> <a href="mailto:ngn13proton@proton.me">Proton email address</a></li>
|
||||
</ul>
|
||||
Or you can add me on XMPP: <c>ngn@chat.ngn13.fun</c>
|
||||
</Card>
|
||||
</div>
|
||||
<Card title="bash donate.sh">
|
||||
If you want to do something stupid with your mone-
|
||||
<br>
|
||||
I mean if you want to support me and my silly little work, here is my monero wallet address:
|
||||
<br>
|
||||
<br>
|
||||
<code>
|
||||
46q7G7u7cmASvJm7AmrhmNg6ctS77mYMmDAy1QxpDn5w57xV3GUY5za4ZPZHAjqaXdfS5YRWm4AVj5UArLDA1retRkJp47F
|
||||
</code>
|
||||
</Card>
|
||||
</main>
|
||||
|
||||
<div class="version">
|
||||
<p>v4.0</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
main{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 35px;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--dark-two);
|
||||
color: white;
|
||||
border-radius: var(--radius);
|
||||
text-shadow: var(--text-shadow);
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.flexbox {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 30px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
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) {
|
||||
.flexbox {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
9
app/src/routes/blog/+page.js
Normal file
9
app/src/routes/blog/+page.js
Normal 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"]
|
||||
}
|
||||
}
|
58
app/src/routes/blog/+page.svelte
Normal file
58
app/src/routes/blog/+page.svelte
Normal file
@ -0,0 +1,58 @@
|
||||
<script>
|
||||
import Header from "../../lib/header.svelte";
|
||||
import CardLink from "../../lib/card_link.svelte";
|
||||
|
||||
export let data
|
||||
let posts = data.posts
|
||||
</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>
|
||||
{#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;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1316px) {
|
||||
main {
|
||||
padding: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
14
app/src/routes/blog/[id]/+page.server.js
Normal file
14
app/src/routes/blog/[id]/+page.server.js
Normal 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"]
|
||||
}
|
165
app/src/routes/blog/[id]/+page.svelte
Normal file
165
app/src/routes/blog/[id]/+page.svelte
Normal file
@ -0,0 +1,165 @@
|
||||
<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] | {data.title}</title>
|
||||
<meta content="[ngn] | blog" property="og:title" />
|
||||
<meta content="{data.content.substring(0, 100)}..." 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;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 80%;
|
||||
padding: 40px;
|
||||
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>
|
41
app/src/routes/services/+page.js
Normal file
41
app/src/routes/services/+page.js
Normal file
@ -0,0 +1,41 @@
|
||||
export async function load({ fetch }) {
|
||||
const api = import.meta.env.VITE_API_URL_DEV
|
||||
const res = await fetch(api+"/services/all")
|
||||
const data = await res.json()
|
||||
|
||||
if (data["error"] != ""){
|
||||
return {
|
||||
error: data["error"]
|
||||
}
|
||||
}
|
||||
|
||||
// Some really bad code to convert
|
||||
// [service1, service2, service3...]
|
||||
// to
|
||||
// [[service1, service2, service3], [service4, service5...]...]
|
||||
// so i can render it in the UI easily
|
||||
|
||||
let all = data["result"]
|
||||
let counter = 0
|
||||
let currentlist = []
|
||||
let services = []
|
||||
|
||||
for (let i = 0; i < all.length; i++){
|
||||
currentlist.push(all[i])
|
||||
counter += 1
|
||||
|
||||
if(i == all.length-1 && counter != 3){
|
||||
services.push(currentlist)
|
||||
}
|
||||
|
||||
if (counter == 3) {
|
||||
services.push(currentlist)
|
||||
currentlist = []
|
||||
counter = 0
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
services
|
||||
}
|
||||
}
|
76
app/src/routes/services/+page.svelte
Normal file
76
app/src/routes/services/+page.svelte
Normal file
@ -0,0 +1,76 @@
|
||||
<script>
|
||||
import Header from "../../lib/header.svelte";
|
||||
import Service from "../../lib/service.svelte";
|
||||
|
||||
export let data
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>[ngn] | services</title>
|
||||
<meta content="[ngn] | services" property="og:title" />
|
||||
<meta content="Stuff that I host" property="og:description" />
|
||||
<meta content="https://ngn.tf" property="og:url" />
|
||||
<meta content="#000000" data-react-helmet="true" name="theme-color" />
|
||||
</svelte:head>
|
||||
<Header><c>ls -l</c> services</Header>
|
||||
<main>
|
||||
<div class="info">
|
||||
<h1></h1>
|
||||
<p>
|
||||
These are free to use FOSS services that I host on my server.
|
||||
If you want an account on any of these services, or if you are having issues with them,
|
||||
please send an email to services@ngn.tf
|
||||
</p>
|
||||
</div>
|
||||
{#each data.services as services_list}
|
||||
<div class="flexrow">
|
||||
{#each services_list as service}
|
||||
<Service url="{service.url}" desc="{service.desc}">{service.name}</Service>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.info h1 {
|
||||
margin-right: 40px;
|
||||
animation-name: colorAnimation;
|
||||
animation-duration: 5s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 40px;
|
||||
color: white;
|
||||
border-radius: var(--radius);
|
||||
font-size: 25px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1316px) {
|
||||
.flexrow {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
BIN
app/static/click.wav
Normal file
BIN
app/static/click.wav
Normal file
Binary file not shown.
13
app/static/font.css
Normal file
13
app/static/font.css
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* fonts are located under /static/fonts, they are from nerdfonts
|
||||
* see nerdfonts.com
|
||||
*
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: "Ubuntu";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("/fonts/UbuntuNerdFont-Regular.ttf");
|
||||
}
|
BIN
app/static/fonts/UbuntuNerdFont-Bold.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-Bold.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-BoldItalic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-Condensed.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-Condensed.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-Italic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-Italic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-Light.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-Light.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-LightItalic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-LightItalic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-Medium.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-Medium.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-MediumItalic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFont-Regular.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFont-Regular.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-Bold.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-Bold.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-BoldItalic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-Condensed.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-Condensed.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-Italic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-Italic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-Light.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-Light.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-LightItalic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-LightItalic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-Medium.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-Medium.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-MediumItalic.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
app/static/fonts/UbuntuNerdFontPropo-Regular.ttf
Normal file
BIN
app/static/fonts/UbuntuNerdFontPropo-Regular.ttf
Normal file
Binary file not shown.
1023
app/static/github.css
Normal file
1023
app/static/github.css
Normal file
File diff suppressed because it is too large
Load Diff
302
app/static/global.css
Normal file
302
app/static/global.css
Normal file
@ -0,0 +1,302 @@
|
||||
@import "./font.css";
|
||||
@import "./github.css";
|
||||
|
||||
:root {
|
||||
--white: white;
|
||||
--dark-one: black;
|
||||
--dark-two: #050505;
|
||||
--dark-three: #121212;
|
||||
--dark-four: #101010;
|
||||
--dark-fife: #3a3b3c;
|
||||
--border-rad: 30px;
|
||||
/*
|
||||
old shadow animation
|
||||
--def-shadow: rgba(0, 0, 0, 0.25) 0px 54px 55px,
|
||||
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;
|
||||
*/
|
||||
--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;
|
||||
}
|
||||
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--dark-one);
|
||||
font-family: "Ubuntu", sans-serif;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: rgba(100, 100, 100, 0.5);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
border-radius: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 10px;
|
||||
background: #181818;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: #282828;
|
||||
}
|
||||
|
||||
@keyframes colorAnimation {
|
||||
100%,
|
||||
0% {
|
||||
color: rgb(255, 0, 0);
|
||||
}
|
||||
8% {
|
||||
color: rgb(255, 127, 0);
|
||||
}
|
||||
16% {
|
||||
color: rgb(255, 255, 0);
|
||||
}
|
||||
25% {
|
||||
color: rgb(127, 255, 0);
|
||||
}
|
||||
33% {
|
||||
color: rgb(0, 255, 0);
|
||||
}
|
||||
41% {
|
||||
color: rgb(0, 255, 127);
|
||||
}
|
||||
50% {
|
||||
color: rgb(0, 255, 255);
|
||||
}
|
||||
58% {
|
||||
color: rgb(0, 127, 255);
|
||||
}
|
||||
66% {
|
||||
color: rgb(0, 0, 255);
|
||||
}
|
||||
75% {
|
||||
color: rgb(127, 0, 255);
|
||||
}
|
||||
83% {
|
||||
color: rgb(255, 0, 255);
|
||||
}
|
||||
91% {
|
||||
color: rgb(255, 0, 127);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes borderAnimation {
|
||||
100%,
|
||||
0% {
|
||||
border-bottom-color: rgb(255, 0, 0);
|
||||
}
|
||||
8% {
|
||||
border-bottom-color: rgb(255, 127, 0);
|
||||
}
|
||||
16% {
|
||||
border-bottom-color: rgb(255, 255, 0);
|
||||
}
|
||||
25% {
|
||||
border-bottom-color: rgb(127, 255, 0);
|
||||
}
|
||||
33% {
|
||||
border-bottom-color: rgb(0, 255, 0);
|
||||
}
|
||||
41% {
|
||||
border-bottom-color: rgb(0, 255, 127);
|
||||
}
|
||||
50% {
|
||||
border-bottom-color: rgb(0, 255, 255);
|
||||
}
|
||||
58% {
|
||||
border-bottom-color: rgb(0, 127, 255);
|
||||
}
|
||||
66% {
|
||||
border-bottom-color: rgb(0, 0, 255);
|
||||
}
|
||||
75% {
|
||||
border-bottom-color: rgb(127, 0, 255);
|
||||
}
|
||||
83% {
|
||||
border-bottom-color: rgb(255, 0, 255);
|
||||
}
|
||||
91% {
|
||||
border-bottom-color: rgb(255, 0, 127);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fullBorderAnimation {
|
||||
100%,
|
||||
0% {
|
||||
border-color: rgb(255, 0, 0);
|
||||
}
|
||||
8% {
|
||||
border-color: rgb(255, 127, 0);
|
||||
}
|
||||
16% {
|
||||
border-color: rgb(255, 255, 0);
|
||||
}
|
||||
25% {
|
||||
border-color: rgb(127, 255, 0);
|
||||
}
|
||||
33% {
|
||||
border-color: rgb(0, 255, 0);
|
||||
}
|
||||
41% {
|
||||
border-color: rgb(0, 255, 127);
|
||||
}
|
||||
50% {
|
||||
border-color: rgb(0, 255, 255);
|
||||
}
|
||||
58% {
|
||||
border-color: rgb(0, 127, 255);
|
||||
}
|
||||
66% {
|
||||
border-color: rgb(0, 0, 255);
|
||||
}
|
||||
75% {
|
||||
border-color: rgb(127, 0, 255);
|
||||
}
|
||||
83% {
|
||||
border-color: rgb(255, 0, 255);
|
||||
}
|
||||
91% {
|
||||
border-color: rgb(255, 0, 127);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gayShadowAnimation {
|
||||
100%,
|
||||
0% {
|
||||
box-shadow: rgba(255, 0, 0, 0.07) 0px 1px 2px,
|
||||
rgba(255, 0, 0, 0.07) 0px 2px 4px, rgba(255, 0, 0, 0.07) 0px 4px 8px,
|
||||
rgba(255, 0, 0, 0.07) 0px 8px 16px, rgba(255, 0, 0, 0.07) 0px 16px 32px,
|
||||
rgba(255, 0, 0, 0.07) 0px 32px 64px;
|
||||
}
|
||||
8% {
|
||||
box-shadow: rgba(255, 127, 0, 0.07) 0px 1px 2px,
|
||||
rgba(255, 127, 0, 0.07) 0px 2px 4px, rgba(255, 127, 0, 0.07) 0px 4px 8px,
|
||||
rgba(255, 127, 0, 0.07) 0px 8px 16px,
|
||||
rgba(255, 127, 0, 0.07) 0px 16px 32px,
|
||||
rgba(255, 127, 0, 0.07) 0px 32px 64px;
|
||||
}
|
||||
16% {
|
||||
box-shadow: rgba(255, 255, 0, 0.07) 0px 1px 2px,
|
||||
rgba(255, 255, 0, 0.07) 0px 2px 4px, rgba(255, 255, 0, 0.07) 0px 4px 8px,
|
||||
rgba(255, 255, 0, 0.07) 0px 8px 16px,
|
||||
rgba(255, 255, 0, 0.07) 0px 16px 32px,
|
||||
rgba(255, 255, 0, 0.07) 0px 32px 64px;
|
||||
}
|
||||
25% {
|
||||
box-shadow: rgba(127, 255, 0, 0.07) 0px 1px 2px,
|
||||
rgba(127, 255, 0, 0.07) 0px 2px 4px, rgba(127, 255, 0, 0.07) 0px 4px 8px,
|
||||
rgba(127, 255, 0, 0.07) 0px 8px 16px,
|
||||
rgba(127, 255, 0, 0.07) 0px 16px 32px,
|
||||
rgba(127, 255, 0, 0.07) 0px 32px 64px;
|
||||
}
|
||||
33% {
|
||||
box-shadow: rgba(0, 255, 0, 0.07) 0px 1px 2px,
|
||||
rgba(0, 255, 0, 0.07) 0px 2px 4px, rgba(0, 255, 0, 0.07) 0px 4px 8px,
|
||||
rgba(0, 255, 0, 0.07) 0px 8px 16px, rgba(0, 255, 0, 0.07) 0px 16px 32px,
|
||||
rgba(0, 255, 0, 0.07) 0px 32px 64px;
|
||||
}
|
||||
41% {
|
||||
box-shadow: rgba(0, 255, 127, 0.07) 0px 1px 2px,
|
||||
rgba(0, 255, 127, 0.07) 0px 2px 4px, rgba(0, 255, 127, 0.07) 0px 4px 8px,
|
||||
rgba(0, 255, 127, 0.07) 0px 8px 16px,
|
||||
rgba(0, 255, 127, 0.07) 0px 16px 32px,
|
||||
rgba(0, 255, 127, 0.07) 0px 32px 64px;
|
||||
}
|
||||
50% {
|
||||
box-shadow: rgba(0, 255, 255, 0.07) 0px 1px 2px,
|
||||
rgba(0, 255, 255, 0.07) 0px 2px 4px, rgba(0, 255, 255, 0.07) 0px 4px 8px,
|
||||
rgba(0, 255, 255, 0.07) 0px 8px 16px,
|
||||
rgba(0, 255, 255, 0.07) 0px 16px 32px,
|
||||
rgba(0, 255, 255, 0.07) 0px 32px 64px;
|
||||
}
|
||||
58% {
|
||||
box-shadow: rgba(0, 127, 255, 0.07) 0px 1px 2px,
|
||||
rgba(0, 127, 255, 0.07) 0px 2px 4px, rgba(0, 127, 255, 0.07) 0px 4px 8px,
|
||||
rgba(0, 127, 255, 0.07) 0px 8px 16px,
|
||||
rgba(0, 127, 255, 0.07) 0px 16px 32px,
|
||||
rgba(0, 127, 255, 0.07) 0px 32px 64px;
|
||||
}
|
||||
66% {
|
||||
box-shadow: rgba(0, 0, 255, 0.07) 0px 1px 2px,
|
||||
rgba(0, 0, 255, 0.07) 0px 2px 4px, rgba(0, 0, 255, 0.07) 0px 4px 8px,
|
||||
rgba(0, 0, 255, 0.07) 0px 8px 16px, rgba(0, 0, 255, 0.07) 0px 16px 32px,
|
||||
rgba(0, 0, 255, 0.07) 0px 32px 64px;
|
||||
}
|
||||
75% {
|
||||
box-shadow: rgba(127, 0, 255, 0.07) 0px 1px 2px,
|
||||
rgba(127, 0, 255, 0.07) 0px 2px 4px, rgba(127, 0, 255, 0.07) 0px 4px 8px,
|
||||
rgba(127, 0, 255, 0.07) 0px 8px 16px,
|
||||
rgba(127, 0, 255, 0.07) 0px 16px 32px,
|
||||
rgba(127, 0, 255, 0.07) 0px 32px 64px;
|
||||
}
|
||||
83% {
|
||||
box-shadow: rgba(255, 0, 255, 0.07) 0px 1px 2px,
|
||||
rgba(255, 0, 255, 0.07) 0px 2px 4px, rgba(255, 0, 255, 0.07) 0px 4px 8px,
|
||||
rgba(255, 0, 255, 0.07) 0px 8px 16px,
|
||||
rgba(255, 0, 255, 0.07) 0px 16px 32px,
|
||||
rgba(255, 0, 255, 0.07) 0px 32px 64px;
|
||||
}
|
||||
91% {
|
||||
box-shadow: rgba(255, 0, 127, 0.07) 0px 1px 2px,
|
||||
rgba(255, 0, 127, 0.07) 0px 2px 4px, rgba(255, 0, 127, 0.07) 0px 4px 8px,
|
||||
rgba(255, 0, 127, 0.07) 0px 8px 16px,
|
||||
rgba(255, 0, 127, 0.07) 0px 16px 32px,
|
||||
rgba(255, 0, 127, 0.07) 0px 32px 64px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes underlineAnimation {
|
||||
100%,
|
||||
0% {
|
||||
text-decoration-color: rgb(255, 0, 0);
|
||||
}
|
||||
8% {
|
||||
text-decoration-color: rgb(255, 127, 0);
|
||||
}
|
||||
16% {
|
||||
text-decoration-color: rgb(255, 255, 0);
|
||||
}
|
||||
25% {
|
||||
text-decoration-color: rgb(127, 255, 0);
|
||||
}
|
||||
33% {
|
||||
text-decoration-color: rgb(0, 255, 0);
|
||||
}
|
||||
41% {
|
||||
text-decoration-color: rgb(0, 255, 127);
|
||||
}
|
||||
50% {
|
||||
text-decoration-color: rgb(0, 255, 255);
|
||||
}
|
||||
58% {
|
||||
text-decoration-color: rgb(0, 127, 255);
|
||||
}
|
||||
66% {
|
||||
text-decoration-color: rgb(0, 0, 255);
|
||||
}
|
||||
75% {
|
||||
text-decoration-color: rgb(127, 0, 255);
|
||||
}
|
||||
83% {
|
||||
text-decoration-color: rgb(255, 0, 255);
|
||||
}
|
||||
91% {
|
||||
text-decoration-color: rgb(255, 0, 127);
|
||||
}
|
||||
}
|
||||
|
||||
.c, c {
|
||||
animation-name: colorAnimation;
|
||||
animation-iteration-count: infinite;
|
||||
animation-duration: 10s;
|
||||
}
|
18
app/svelte.config.js
Normal file
18
app/svelte.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
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()
|
||||
},
|
||||
|
||||
onwarn: (warning, handler) => {
|
||||
if (warning.code === "a11y-click-events-have-key-events") return
|
||||
handler(warning)
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
6
app/vite.config.js
Normal file
6
app/vite.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
Reference in New Issue
Block a user