@ -1,32 +1,17 @@
|
||||
# build the application with node
|
||||
FROM node:23.11.0 AS build
|
||||
|
||||
# app URLs
|
||||
ARG WEBSITE_APP_URL_CLEAR
|
||||
ARG WEBSITE_APP_URL_ONION
|
||||
ARG WEBSITE_APP_URL_I2P
|
||||
|
||||
ENV WEBSITE_APP_URL_CLEAR=$WEBSITE_APP_URL_CLEAR
|
||||
ENV WEBSITE_APP_URL_ONION=$WEBSITE_APP_URL_ONION
|
||||
ENV WEBSITE_APP_URL_I2P=$WEBSITE_APP_URL_I2P
|
||||
|
||||
# API URLs
|
||||
ARG WEBSITE_API_URL_CLEAR
|
||||
ARG WEBSITE_API_URL_ONION
|
||||
ARG WEBSITE_API_URL_I2P
|
||||
|
||||
ENV WEBSITE_API_URL_CLEAR=$WEBSITE_API_URL_CLEAR
|
||||
ENV WEBSITE_API_URL_ONION=$WEBSITE_API_URL_ONION
|
||||
ENV WEBSITE_API_URL_I2P=$WEBSITE_API_URL_I2P
|
||||
|
||||
# other config
|
||||
ARG WEBSITE_REPORT_URL
|
||||
ARG WEBSITE_SOURCE_URL
|
||||
ARG WEBSITE_DOC_URL
|
||||
ARG WEBSITE_API_URL
|
||||
ARG WEBSITE_API_PATH
|
||||
|
||||
ENV WEBSITE_REPORT_URL=$WEBSITE_REPORT_URL
|
||||
ENV WEBSITE_SOURCE_URL=$WEBSITE_SOURCE_URL
|
||||
ENV WEBSITE_DOC_URL=$WEBSITE_DOC_URL
|
||||
ENV WEBSITE_API_URL=$WEBSITE_API_URL
|
||||
ENV WEBSITE_API_PATH=$WEBSITE_API_PATH
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
|
@ -1,9 +1,14 @@
|
||||
import { urljoin, env_url } from "$lib/util.js";
|
||||
import { browser } from "$app/environment";
|
||||
import { urljoin } from "$lib/util.js";
|
||||
|
||||
const api_version = "v1";
|
||||
|
||||
function api_urljoin(path = null, query = {}) {
|
||||
let api_url = urljoin(env_url("API"), api_version);
|
||||
let api_url = "";
|
||||
|
||||
if (browser) api_url = urljoin(import.meta.env.WEBSITE_API_PATH, api_version);
|
||||
else api_url = urljoin(import.meta.env.WEBSITE_API_URL, api_version);
|
||||
|
||||
return urljoin(api_url, path, query);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { urljoin, env_url } from "$lib/util.js";
|
||||
import { urljoin } from "$lib/util.js";
|
||||
|
||||
function doc_urljoin(path = null, query = {}) {
|
||||
return urljoin(import.meta.env.WEBSITE_DOC_URL, path, query);
|
||||
|
@ -1,14 +1,16 @@
|
||||
<script>
|
||||
import { app_url, color, date_from_ts } from "$lib/util.js";
|
||||
import { color, date_from_ts } from "$lib/util.js";
|
||||
import { api_get_metrics } from "$lib/api.js";
|
||||
import Link from "$lib/link.svelte";
|
||||
|
||||
import { onMount } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
let data = {};
|
||||
let show_counter = false,
|
||||
data = {};
|
||||
|
||||
onMount(async () => {
|
||||
show_counter = true;
|
||||
data = await api_get_metrics(fetch);
|
||||
});
|
||||
</script>
|
||||
@ -20,24 +22,28 @@
|
||||
</span>
|
||||
<span>/</span>
|
||||
<span>
|
||||
<Link link={app_url("/doc/license")} bold={true}>{$_("footer.license")}</Link>
|
||||
<Link link="/doc/license" bold={true}>{$_("footer.license")}</Link>
|
||||
</span>
|
||||
<span>/</span>
|
||||
<span>
|
||||
<Link link={app_url("/doc/privacy")} bold={true}>{$_("footer.privacy")}</Link>
|
||||
<Link link="/doc/privacy" bold={true}>{$_("footer.privacy")}</Link>
|
||||
</span>
|
||||
</div>
|
||||
<span class="counter">
|
||||
{$_("footer.number", {
|
||||
values: {
|
||||
total: data.total,
|
||||
since: date_from_ts(data.since),
|
||||
},
|
||||
})}
|
||||
{#if data.number % 1000 == 0}
|
||||
<span style="color: var(--{color()})">({$_("footer.wow")})</span>
|
||||
{/if}
|
||||
</span>
|
||||
{#if show_counter}
|
||||
<span class="counter">
|
||||
{$_("footer.number", {
|
||||
values: {
|
||||
total: data.total,
|
||||
since: date_from_ts(data.since),
|
||||
},
|
||||
})}
|
||||
{#if data.number % 1000 == 0}
|
||||
<span style="color: var(--{color()})">({$_("footer.wow")})</span>
|
||||
{/if}
|
||||
</span>
|
||||
{:else}
|
||||
<span class="counter">{$_("footer.js")}</span>
|
||||
{/if}
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
|
@ -1,7 +1,5 @@
|
||||
<script>
|
||||
import { api_urljoin } from "$lib/api.js";
|
||||
import { app_url } from "$lib/util.js";
|
||||
|
||||
export let desc, title;
|
||||
</script>
|
||||
|
||||
@ -16,7 +14,6 @@
|
||||
|
||||
<meta property="og:title" content="[ngn.tf] | {title}" />
|
||||
<meta property="og:description" content={desc} />
|
||||
<meta property="og:url" content={app_url()} />
|
||||
|
||||
<link
|
||||
rel="alternate"
|
||||
|
@ -1,12 +1,14 @@
|
||||
<script>
|
||||
import { browser } from "$app/environment";
|
||||
import { color } from "$lib/util.js";
|
||||
import { onMount } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let picture = "";
|
||||
export let title = "";
|
||||
|
||||
let title_cur = "";
|
||||
let title_cur = title;
|
||||
let show_animation = false;
|
||||
|
||||
function animate(title) {
|
||||
if (!browser) return;
|
||||
@ -24,13 +26,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
show_animation = true;
|
||||
});
|
||||
|
||||
$: animate(title);
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<div>
|
||||
<h1 class="title" style="color: var(--{color()})">{title_cur}</h1>
|
||||
<h1 class="cursor" style="color: var(--{color()})">_</h1>
|
||||
{#if show_animation}
|
||||
<h1 class="title" style="color: var(--{color()})">{title_cur}</h1>
|
||||
<h1 class="cursor" style="color: var(--{color()})">_</h1>
|
||||
{:else}
|
||||
<h1 class="title" style="color: var(--{color()})">{title}</h1>
|
||||
{/if}
|
||||
</div>
|
||||
<img src="/profile/{picture}.png" alt="" />
|
||||
</header>
|
||||
|
@ -1,7 +1,9 @@
|
||||
<script>
|
||||
import { locale_list, locale_select, locale_index } from "$lib/locale.js";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let len = locale_list.length;
|
||||
let show = false;
|
||||
|
||||
function get_next(indx) {
|
||||
let new_indx = 0;
|
||||
@ -15,11 +17,17 @@
|
||||
function next() {
|
||||
locale_select(get_next($locale_index).code);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
show = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<button on:click={next}>
|
||||
{get_next($locale_index).icon}
|
||||
</button>
|
||||
{#if show}
|
||||
<button on:click={next}>
|
||||
{get_next($locale_index).icon}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
button {
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { locale_from_browser } from "$lib/locale.js";
|
||||
import { browser } from "$app/environment";
|
||||
import { page } from "$app/state";
|
||||
|
||||
const colors = [
|
||||
"yellow",
|
||||
@ -25,34 +23,14 @@ function click() {
|
||||
audio.play();
|
||||
}
|
||||
|
||||
function urljoin(url, path = null, query = {}) {
|
||||
function urljoin(url, path = null) {
|
||||
if (undefined === url || null === url) return;
|
||||
|
||||
let url_len = url.length;
|
||||
if (url[url.length - 1] != "/") url += "/";
|
||||
|
||||
if (url[url_len - 1] != "/") url += "/";
|
||||
|
||||
if (null === path || "" === path) url = new URL(url);
|
||||
else if (path[0] === "/") url = new URL(path.slice(1), url);
|
||||
else url = new URL(path, url);
|
||||
|
||||
for (let k in query) url.searchParams.append(k, query[k]);
|
||||
|
||||
return url.href;
|
||||
}
|
||||
|
||||
function env_url(prefix) {
|
||||
let host = "";
|
||||
|
||||
if (browser) host = window.location.hostname;
|
||||
|
||||
if (host.endsWith(".onion")) return import.meta.env["WEBSITE_" + prefix + "_URL_ONION"];
|
||||
else if (host.endsWith(".i2p")) return import.meta.env["WEBSITE_" + prefix + "_URL_I2P"];
|
||||
else return import.meta.env["WEBSITE_" + prefix + "_URL_CLEAR"];
|
||||
}
|
||||
|
||||
function app_url(path = null, query = {}) {
|
||||
return urljoin(env_url("APP"), path, query);
|
||||
if (null === path || "" === path) return url;
|
||||
if (path[0] === "/") return url + path.slice(1);
|
||||
return url + path;
|
||||
}
|
||||
|
||||
function time_from_ts(ts) {
|
||||
@ -80,4 +58,4 @@ function date_from_ts(ts) {
|
||||
}).format(new Date(ts * 1000));
|
||||
}
|
||||
|
||||
export { color, click, urljoin, env_url, app_url, time_from_ts, date_from_ts };
|
||||
export { color, click, urljoin, time_from_ts, date_from_ts };
|
||||
|
@ -73,6 +73,7 @@
|
||||
"license": "License",
|
||||
"privacy": "Privacy",
|
||||
"number": "Visited {total} times since {since}",
|
||||
"wow": "wow!!"
|
||||
"wow": "wow!!",
|
||||
"js": "Enable javascript to display all the elements"
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,7 @@
|
||||
"license": "Lisans",
|
||||
"privacy": "Gizlilik",
|
||||
"number": "{since} tarihinden beri {total} kez ziyaret edildi",
|
||||
"wow": "vay be!!"
|
||||
"wow": "vay be!!",
|
||||
"js": "Tüm elementleri görüntelemek için javascript'i açın"
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
import { api_urljoin } from "$lib/api.js";
|
||||
import { locale, _ } from "svelte-i18n";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let { data } = $props();
|
||||
let services = $state(data.services);
|
||||
let show_input = $state(false);
|
||||
|
||||
function change(input) {
|
||||
let value = input.target.value.toLowerCase();
|
||||
@ -31,6 +33,10 @@
|
||||
return s.desc[$locale] !== "" && s.desc[$locale] !== null && s.desc[$locale] !== undefined;
|
||||
});
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
show_input = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<Head title="services" desc="my self-hosted services and projects" />
|
||||
@ -41,7 +47,9 @@
|
||||
{:else}
|
||||
<main>
|
||||
<div class="title">
|
||||
<input oninput={change} type="text" placeholder={$_("services.search")} />
|
||||
{#if show_input}
|
||||
<input oninput={change} type="text" placeholder={$_("services.search")} />
|
||||
{/if}
|
||||
<div>
|
||||
<Link icon="nf-fa-feed" link={api_urljoin("/news/" + $locale)}>{$_("services.feed")}</Link>
|
||||
</div>
|
||||
|
@ -24,15 +24,9 @@ const default_env = {
|
||||
source_url: "https://git.ngn.tf/ngn/website",
|
||||
report_url: "https://git.ngn.tf/ngn/website/issues",
|
||||
doc_url: "http://localhost:7003",
|
||||
app_url: {
|
||||
clear: "http://localhost:7001",
|
||||
onion: "",
|
||||
i2p: "",
|
||||
},
|
||||
api_url: {
|
||||
clear: "http://localhost:7002",
|
||||
onion: "",
|
||||
i2p: "",
|
||||
api: {
|
||||
url: "http://localhost:7002",
|
||||
path: "http://localhost:7002",
|
||||
},
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user