This commit is contained in:
ngn
2023-11-12 17:43:23 +03:00
parent 8c1552d639
commit 498a54cd20
68 changed files with 1983 additions and 301 deletions

11
app/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=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
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>

View 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
View 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
View 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>

View 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>

View 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>

View File

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

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>

139
app/src/routes/+page.svelte Normal file
View 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>

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,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>

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,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>

View 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
}
}

View 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>