add projects and metrics routes
This commit is contained in:
@ -1,7 +0,0 @@
|
||||
import { locale } from "svelte-i18n";
|
||||
|
||||
export const handle = async ({ event, resolve }) => {
|
||||
const lang = event.request.headers.get("accept-language")?.split(",")[0];
|
||||
if (lang) locale.set(lang);
|
||||
return resolve(event);
|
||||
};
|
@ -22,12 +22,16 @@ async function GET(fetch, url) {
|
||||
return json["result"];
|
||||
}
|
||||
|
||||
async function visitor(fetch) {
|
||||
return GET(fetch, api_url("/visitor"));
|
||||
async function get_metrics(fetch) {
|
||||
return GET(fetch, api_url("/metrics"));
|
||||
}
|
||||
|
||||
async function services(fetch) {
|
||||
async function get_services(fetch) {
|
||||
return GET(fetch, api_url("/services"));
|
||||
}
|
||||
|
||||
export { version, api_url, visitor, services };
|
||||
async function get_projects(fetch) {
|
||||
return GET(fetch, api_url("/projects"));
|
||||
}
|
||||
|
||||
export { version, api_url, get_metrics, get_services, get_projects };
|
||||
|
@ -1,74 +0,0 @@
|
||||
<script>
|
||||
import { click } from "$lib/util.js";
|
||||
export let title;
|
||||
export let url;
|
||||
|
||||
let current = "";
|
||||
let i = 0;
|
||||
|
||||
while (title.length > i) {
|
||||
let c = title[i];
|
||||
setTimeout(
|
||||
() => {
|
||||
current += c;
|
||||
},
|
||||
100 * (i + 1)
|
||||
);
|
||||
i += 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<a on:click={click} data-sveltekit-preload-data href={url}>
|
||||
<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: var(--radius);
|
||||
cursor: pointer;
|
||||
transition: 0.4s;
|
||||
text-decoration: none;
|
||||
border: solid 1px var(--border-color);
|
||||
}
|
||||
|
||||
a:hover > .title {
|
||||
text-shadow: var(--text-shadow);
|
||||
}
|
||||
|
||||
.title {
|
||||
border: solid 1px var(--dark-two);
|
||||
background: var(--dark-two);
|
||||
padding: 25px;
|
||||
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: 30px;
|
||||
padding-top: 30px;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
font-size: 25px;
|
||||
}
|
||||
</style>
|
@ -1,14 +1,15 @@
|
||||
<script>
|
||||
import { color, date_from_ts } from "$lib/util.js";
|
||||
import { get_metrics } from "$lib/api.js";
|
||||
import Link from "$lib/link.svelte";
|
||||
|
||||
import { onMount } from "svelte";
|
||||
import { visitor } from "$lib/api.js";
|
||||
import { color } from "$lib/util.js";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
let visitor_count = 0;
|
||||
let data = {};
|
||||
|
||||
onMount(async () => {
|
||||
visitor_count = await visitor(fetch);
|
||||
data = await get_metrics(fetch);
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -33,8 +34,13 @@
|
||||
</div>
|
||||
<div class="useless">
|
||||
<span>
|
||||
{$_("footer.number", { values: { count: visitor_count } })}
|
||||
{#if visitor_count % 1000 == 0}
|
||||
{$_("footer.number", {
|
||||
values: {
|
||||
number: data.number,
|
||||
since: date_from_ts(data.since),
|
||||
},
|
||||
})}
|
||||
{#if data.number % 1000 == 0}
|
||||
<span style="color: var(--{color()})">({$_("footer.congrat")})</span>
|
||||
{/if}
|
||||
</span>
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { locale } from "svelte-i18n";
|
||||
import { language, set_lang } from "$lib/util.js";
|
||||
import languages from "$lib/lang.js";
|
||||
|
||||
let icon = "",
|
||||
indx = 0,
|
||||
len = languages.length;
|
||||
@ -9,18 +10,20 @@
|
||||
if (indx >= languages.length) indx = 0;
|
||||
|
||||
icon = languages[indx].icon;
|
||||
locale.set(languages[indx++].code);
|
||||
set_lang(languages[indx++].code);
|
||||
}
|
||||
|
||||
for (indx = 0; indx < len; indx++) {
|
||||
if (languages[indx].code == $locale.slice(0, 2)) {
|
||||
if (languages[indx].code == $language) {
|
||||
icon = languages[indx++].icon;
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={next}>{icon}</button>
|
||||
<button on:click={next}>
|
||||
{icon}
|
||||
</button>
|
||||
|
||||
<style>
|
||||
button {
|
||||
|
@ -2,8 +2,8 @@
|
||||
import Icon from "$lib/icon.svelte";
|
||||
import Link from "$lib/link.svelte";
|
||||
|
||||
import { color, time_from_ts } from "$lib/util.js";
|
||||
import { _, locale } from "svelte-i18n";
|
||||
import { color, time_from_ts, language } from "$lib/util.js";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let service = {};
|
||||
let style = "";
|
||||
@ -15,7 +15,7 @@
|
||||
<div class="info">
|
||||
<div class="title">
|
||||
<h1>{service.name}</h1>
|
||||
<p>{service.desc[$locale.slice(0, 2)]}</p>
|
||||
<p>{service.desc[$language]}</p>
|
||||
</div>
|
||||
<div class="links">
|
||||
<Link highlight={false} link={service.clear}><Icon icon="nf-oct-link" /></Link>
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { browser } from "$app/environment";
|
||||
import { locale } from "svelte-i18n";
|
||||
import languages from "$lib/lang.js";
|
||||
import { writable, get } from "svelte/store";
|
||||
|
||||
const default_lang = "en";
|
||||
const default_language = languages[0].code;
|
||||
const colors = [
|
||||
"yellow",
|
||||
"cyan",
|
||||
@ -10,8 +13,33 @@ const colors = [
|
||||
// "blue" (looks kinda ass)
|
||||
];
|
||||
|
||||
let language = writable(default_language);
|
||||
let colors_pos = -1;
|
||||
|
||||
function browser_lang() {
|
||||
if (browser) return window.navigator.language.slice(0, 2).toLowerCase();
|
||||
else return get(language);
|
||||
}
|
||||
|
||||
function set_lang(lang) {
|
||||
language.set(default_language);
|
||||
|
||||
if (lang === null || lang === undefined) {
|
||||
if (browser) set_lang(browser_lang());
|
||||
return;
|
||||
}
|
||||
|
||||
lang = lang.slice(0, 2);
|
||||
|
||||
for (let i = 0; i < languages.length; i++) {
|
||||
if (lang === languages[i].code) {
|
||||
language.set(lang);
|
||||
locale.set(lang);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function urljoin(url, path = null, query = {}) {
|
||||
let url_len = url.length;
|
||||
|
||||
@ -42,13 +70,40 @@ function click() {
|
||||
audio.play();
|
||||
}
|
||||
|
||||
function browser_lang() {
|
||||
if (browser) return window.navigator.language.slice(0, 2).toLowerCase();
|
||||
return default_lang;
|
||||
}
|
||||
|
||||
function time_from_ts(ts) {
|
||||
return new Date(ts * 1000).toLocaleTimeString();
|
||||
if (ts === 0 || ts === undefined) return;
|
||||
|
||||
let ts_date = new Date(ts * 1000);
|
||||
let ts_zone = ts_date.toString().match(/([A-Z]+[\+-][0-9]+)/)[1];
|
||||
|
||||
return (
|
||||
new Intl.DateTimeFormat(browser_lang(), {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
}).format(ts_date) + ` (${ts_zone})`
|
||||
);
|
||||
}
|
||||
|
||||
export { urljoin, frontend_url, browser_lang, click, color, time_from_ts };
|
||||
function date_from_ts(ts) {
|
||||
if (ts === 0 || ts === undefined) return;
|
||||
|
||||
return new Intl.DateTimeFormat(browser_lang(), {
|
||||
month: "2-digit",
|
||||
year: "2-digit",
|
||||
day: "2-digit",
|
||||
}).format(new Date(ts * 1000));
|
||||
}
|
||||
|
||||
export {
|
||||
default_language,
|
||||
browser_lang,
|
||||
language,
|
||||
set_lang,
|
||||
urljoin,
|
||||
frontend_url,
|
||||
click,
|
||||
color,
|
||||
time_from_ts,
|
||||
date_from_ts,
|
||||
};
|
||||
|
@ -18,6 +18,7 @@
|
||||
"title": "work",
|
||||
"desc": "I don't currently have a job, so I spend most of my time...",
|
||||
"build": "building stupid shit",
|
||||
"fix": "fixing stupid shit",
|
||||
"ctf": "solving CTF challenges",
|
||||
"contribute": "contributing to random projects",
|
||||
"wiki": "expanding my wiki"
|
||||
@ -25,16 +26,20 @@
|
||||
"links": {
|
||||
"title": "contact",
|
||||
"desc": "Here are some useful links if you want to get in contact with me",
|
||||
"prefer": "preferred"
|
||||
"prefer": "I highly prefer email, you can send encrypted emails using my PGP key"
|
||||
},
|
||||
"info": {
|
||||
"services": {
|
||||
"title": "services",
|
||||
"desc": "A part from working on stupid shit, I host free (as in freedom, and price) services available for all",
|
||||
"speed": "All of these services are available over a 600 Mbit/s interface",
|
||||
"security": "All use SSL encrypted connection and they are all privacy-respecting",
|
||||
"privacy": "Accessible from clearnet, TOR and I2P, no region or network blocks",
|
||||
"bullshit": "No CDNs, no cloudflare, no CAPTCHA, no analytics, no bullshit",
|
||||
"link": "see all the services"
|
||||
"link": "Check them out!"
|
||||
},
|
||||
"projects": {
|
||||
"title": "projects",
|
||||
"desc": "I mostly work on free software projects, here are some of projects that you might find interesting"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
@ -68,7 +73,7 @@
|
||||
"license": "License",
|
||||
"privacy": "Privacy",
|
||||
"powered": "Powered by Svelte, Go, SQLite and donations",
|
||||
"number": "You are the visitor number {count}",
|
||||
"number": "You are the visitor number {number} since {since}",
|
||||
"congrat": "congrats!!",
|
||||
"version": "Using API version {api_version}, frontend version {frontend_version}"
|
||||
}
|
||||
|
@ -39,7 +39,7 @@
|
||||
"license": "Lisans",
|
||||
"privacy": "Gizlilik",
|
||||
"powered": "Svelte, Go, SQLite ve yemek param tarafından destekleniyor",
|
||||
"number": "{count}. ziyaretçisiniz",
|
||||
"number": "{since} tarihinden beri {number}. ziyaretçisiniz",
|
||||
"congrat": "tebrikler!!",
|
||||
"version": "Kullan API versiyonu {api_version}, arayüz versiyonu {frontend_version}"
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
import { init, register, waitLocale } from "svelte-i18n";
|
||||
import { browser_lang } from "$lib/util.js";
|
||||
import { services } from "$lib/api.js";
|
||||
import { default_language, language, set_lang } from "$lib/util.js";
|
||||
import { get_services, get_projects } from "$lib/api.js";
|
||||
import languages from "$lib/lang.js";
|
||||
|
||||
import { init, register, waitLocale } from "svelte-i18n";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
// setup the locale
|
||||
for (let i = 0; i < languages.length; i++)
|
||||
register(languages[i].code, () => import(/* @vite-ignore */ languages[i].path));
|
||||
|
||||
// set the language
|
||||
set_lang();
|
||||
|
||||
init({
|
||||
fallbackLocale: languages[0].code,
|
||||
initialLocale: browser_lang(),
|
||||
fallbackLocale: default_language,
|
||||
initialLocale: get(language),
|
||||
});
|
||||
|
||||
// load locales & load data from the API
|
||||
@ -18,7 +23,8 @@ export async function load({ fetch }) {
|
||||
|
||||
try {
|
||||
return {
|
||||
services: await services(fetch),
|
||||
services: await get_services(fetch),
|
||||
projects: await get_projects(fetch),
|
||||
error: null,
|
||||
};
|
||||
} catch (err) {
|
||||
|
@ -4,8 +4,11 @@
|
||||
import Card from "$lib/card.svelte";
|
||||
import Link from "$lib/link.svelte";
|
||||
|
||||
import { color } from "$lib/util.js";
|
||||
import { color, language } from "$lib/util.js";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
const { data } = $props();
|
||||
let projects = $state(data.projects);
|
||||
</script>
|
||||
|
||||
<Head title="home" desc="home page of my personal website" />
|
||||
@ -24,6 +27,7 @@
|
||||
<span>{$_("home.work.desc")}</span>
|
||||
<ul>
|
||||
<li>⌨️ {$_("home.work.build")}</li>
|
||||
<li>🤦 {$_("home.work.fix")}</li>
|
||||
<li>🚩 {$_("home.work.ctf")}</li>
|
||||
<li>👥 {$_("home.work.contribute")}</li>
|
||||
<li>📑 {$_("home.work.wiki")}</li>
|
||||
@ -37,44 +41,53 @@
|
||||
PGP
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link icon="nf-md-email" link="mailto:ngn@ngn.tf">Email</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link icon="nf-md-mastodon" link="https://defcon.social/@ngn">Mastodon</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<span>
|
||||
{$_("home.links.prefer")}
|
||||
</span>
|
||||
</Card>
|
||||
<Card title={$_("home.services.title")}>
|
||||
<span>
|
||||
{$_("home.services.desc")}
|
||||
</span>
|
||||
<ul>
|
||||
<li>
|
||||
<Link icon="nf-cod-github" link="https://github.com/ngn13">Github</Link>
|
||||
<i style="color: var(--{color()});" class="nf nf-md-speedometer_slow"></i>
|
||||
{$_("home.services.speed")}
|
||||
</li>
|
||||
<li>
|
||||
<Link icon="nf-md-email" link="mailto:ngn@ngn.tf">Email</Link>
|
||||
<span class="prefer">({$_("home.links.prefer")})</span>
|
||||
<i style="color: var(--{color()});" class="nf nf-fa-lock"></i>
|
||||
{$_("home.services.security")}
|
||||
</li>
|
||||
<li>
|
||||
<i style="color: var(--{color()});" class="nf nf-fa-network_wired"></i>
|
||||
{$_("home.services.privacy")}
|
||||
</li>
|
||||
<li>
|
||||
<i style="color: var(--{color()});" class="nf nf-md-eye_off"></i>
|
||||
{$_("home.services.bullshit")}
|
||||
</li>
|
||||
</ul>
|
||||
<Link linK="/services">{$_("home.services.link")}</Link>
|
||||
</Card>
|
||||
<Card title={$_("home.info.title")}>
|
||||
<div class="services">
|
||||
<div class="info">
|
||||
<span>
|
||||
{$_("home.info.desc")}
|
||||
</span>
|
||||
<ul>
|
||||
<li>
|
||||
<i style="color: var(--{color()});" class="nf nf-md-speedometer_slow"></i>
|
||||
{$_("home.info.speed")}
|
||||
</li>
|
||||
<li>
|
||||
<i style="color: var(--{color()});" class="nf nf-fa-lock"></i>
|
||||
{$_("home.info.security")}
|
||||
</li>
|
||||
<li>
|
||||
<i style="color: var(--{color()});" class="nf nf-fa-network_wired"></i>
|
||||
{$_("home.info.privacy")}
|
||||
</li>
|
||||
<li>
|
||||
<i style="color: var(--{color()});" class="nf nf-md-eye_off"></i>
|
||||
{$_("home.info.bullshit")}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<Card title={$_("home.projects.title")}>
|
||||
<span>
|
||||
{$_("home.projects.desc")}:
|
||||
</span>
|
||||
<ul>
|
||||
{#each projects as project}
|
||||
<li>
|
||||
<Link active={true} link={project.url}>{project.name}</Link>:
|
||||
{project.desc[$language]}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</Card>
|
||||
</main>
|
||||
|
||||
@ -89,25 +102,6 @@
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
.prefer {
|
||||
color: var(--white-2);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.services {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
.services .info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 900px) {
|
||||
main {
|
||||
flex-direction: column;
|
||||
|
@ -4,24 +4,25 @@
|
||||
import Link from "$lib/link.svelte";
|
||||
import Head from "$lib/head.svelte";
|
||||
|
||||
import { _, locale } from "svelte-i18n";
|
||||
import { language } from "$lib/util.js";
|
||||
import { api_url } from "$lib/api.js";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
let { data } = $props();
|
||||
let list = $state(data.services);
|
||||
let services = $state(data.services);
|
||||
|
||||
function change(input) {
|
||||
let value = input.target.value.toLowerCase();
|
||||
list = [];
|
||||
services = [];
|
||||
|
||||
if (value === "") {
|
||||
list = data.services;
|
||||
services = data.services;
|
||||
return;
|
||||
}
|
||||
|
||||
data.services.forEach((s) => {
|
||||
if (s.name.toLowerCase().includes(value)) list.push(s);
|
||||
else if (s.desc[$locale.slice(0, 2)].toLowerCase().includes(value)) list.push(s);
|
||||
if (s.name.toLowerCase().includes(value)) services.push(s);
|
||||
else if (s.desc[$language].toLowerCase().includes(value)) services.push(s);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -33,13 +34,11 @@
|
||||
<div class="title">
|
||||
<input oninput={change} type="text" placeholder={$_("services.search")} />
|
||||
<div>
|
||||
<Link icon="nf-fa-feed" link={api_url("/news/" + $locale.slice(0, 2))}
|
||||
>{$_("services.feed")}</Link
|
||||
>
|
||||
<Link icon="nf-fa-feed" link={api_url("/news/" + $language)}>{$_("services.feed")}</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="services">
|
||||
{#each list as service}
|
||||
{#each services as service}
|
||||
<Service {service} />
|
||||
{/each}
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user