From 4311b82976d0263270e25c9e0c7a4a37240e0f0d Mon Sep 17 00:00:00 2001 From: core Date: Sun, 19 Feb 2023 23:23:19 -0500 Subject: [PATCH] ui work --- tfweb/.eslintignore | 13 + tfweb/.eslintrc.cjs | 20 + tfweb/.gitignore | 10 + tfweb/.idea/.gitignore | 5 + .../inspectionProfiles/Project_Default.xml | 6 + tfweb/.idea/modules.xml | 8 + tfweb/.idea/tfweb.iml | 12 + tfweb/.idea/vcs.xml | 6 + tfweb/.npmrc | 1 + tfweb/package.json | 34 + tfweb/postcss.config.cjs | 6 + tfweb/src/app.css | 3 + tfweb/src/app.d.ts | 12 + tfweb/src/app.html | 12 + tfweb/src/components/Badge.svelte | 6 + tfweb/src/components/Header.svelte | 93 + tfweb/src/components/Theme.svelte | 24 + tfweb/src/i18n/en.json | 13 + tfweb/src/i18n/jp.json | 13 + tfweb/src/i18n/nl.json | 13 + tfweb/src/routes/+layout.svelte | 11 + tfweb/src/routes/auth/login/+page.svelte | 3 + tfweb/src/scripts/PersistentStore.ts | 11 + tfweb/src/scripts/i18n.ts | 50 + tfweb/src/scripts/logger.ts | 118 ++ tfweb/src/stores/LocaleStore.ts | 3 + tfweb/src/stores/ThemeStore.ts | 3 + tfweb/static/favicon.png | Bin 0 -> 1571 bytes tfweb/svelte.config.js | 15 + tfweb/tailwind.config.cjs | 22 + tfweb/tsconfig.json | 17 + tfweb/vite.config.ts | 6 + tfweb/yarn.lock | 1736 +++++++++++++++++ 33 files changed, 2305 insertions(+) create mode 100644 tfweb/.eslintignore create mode 100644 tfweb/.eslintrc.cjs create mode 100644 tfweb/.gitignore create mode 100644 tfweb/.idea/.gitignore create mode 100644 tfweb/.idea/inspectionProfiles/Project_Default.xml create mode 100644 tfweb/.idea/modules.xml create mode 100644 tfweb/.idea/tfweb.iml create mode 100644 tfweb/.idea/vcs.xml create mode 100644 tfweb/.npmrc create mode 100644 tfweb/package.json create mode 100644 tfweb/postcss.config.cjs create mode 100644 tfweb/src/app.css create mode 100644 tfweb/src/app.d.ts create mode 100644 tfweb/src/app.html create mode 100644 tfweb/src/components/Badge.svelte create mode 100644 tfweb/src/components/Header.svelte create mode 100644 tfweb/src/components/Theme.svelte create mode 100644 tfweb/src/i18n/en.json create mode 100644 tfweb/src/i18n/jp.json create mode 100644 tfweb/src/i18n/nl.json create mode 100644 tfweb/src/routes/+layout.svelte create mode 100644 tfweb/src/routes/auth/login/+page.svelte create mode 100644 tfweb/src/scripts/PersistentStore.ts create mode 100644 tfweb/src/scripts/i18n.ts create mode 100644 tfweb/src/scripts/logger.ts create mode 100644 tfweb/src/stores/LocaleStore.ts create mode 100644 tfweb/src/stores/ThemeStore.ts create mode 100644 tfweb/static/favicon.png create mode 100644 tfweb/svelte.config.js create mode 100644 tfweb/tailwind.config.cjs create mode 100644 tfweb/tsconfig.json create mode 100644 tfweb/vite.config.ts create mode 100644 tfweb/yarn.lock diff --git a/tfweb/.eslintignore b/tfweb/.eslintignore new file mode 100644 index 0000000..3897265 --- /dev/null +++ b/tfweb/.eslintignore @@ -0,0 +1,13 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/tfweb/.eslintrc.cjs b/tfweb/.eslintrc.cjs new file mode 100644 index 0000000..13b6414 --- /dev/null +++ b/tfweb/.eslintrc.cjs @@ -0,0 +1,20 @@ +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + plugins: ['svelte3', '@typescript-eslint'], + ignorePatterns: ['*.cjs'], + overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], + settings: { + 'svelte3/typescript': () => require('typescript') + }, + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020 + }, + env: { + browser: true, + es2017: true, + node: true + } +}; diff --git a/tfweb/.gitignore b/tfweb/.gitignore new file mode 100644 index 0000000..6635cf5 --- /dev/null +++ b/tfweb/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/tfweb/.idea/.gitignore b/tfweb/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/tfweb/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/tfweb/.idea/inspectionProfiles/Project_Default.xml b/tfweb/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/tfweb/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/tfweb/.idea/modules.xml b/tfweb/.idea/modules.xml new file mode 100644 index 0000000..de9d92c --- /dev/null +++ b/tfweb/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tfweb/.idea/tfweb.iml b/tfweb/.idea/tfweb.iml new file mode 100644 index 0000000..0c8867d --- /dev/null +++ b/tfweb/.idea/tfweb.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/tfweb/.idea/vcs.xml b/tfweb/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/tfweb/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/tfweb/.npmrc b/tfweb/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/tfweb/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/tfweb/package.json b/tfweb/package.json new file mode 100644 index 0000000..b9af103 --- /dev/null +++ b/tfweb/package.json @@ -0,0 +1,34 @@ +{ + "name": "tfweb", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "eslint .", + "typesafe-i18n": "typesafe-i18n" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^2.0.0", + "@sveltejs/kit": "^1.5.0", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", + "autoprefixer": "^10.4.13", + "eslint": "^8.28.0", + "eslint-plugin-svelte3": "^4.0.0", + "postcss": "^8.4.21", + "svelte": "^3.54.0", + "svelte-check": "^3.0.1", + "tailwindcss": "^3.2.7", + "tslib": "^2.4.1", + "typescript": "^4.9.5", + "vite": "^4.0.0" + }, + "type": "module", + "dependencies": { + "a17t": "^0.10.1" + } +} diff --git a/tfweb/postcss.config.cjs b/tfweb/postcss.config.cjs new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/tfweb/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/tfweb/src/app.css b/tfweb/src/app.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/tfweb/src/app.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/tfweb/src/app.d.ts b/tfweb/src/app.d.ts new file mode 100644 index 0000000..f59b884 --- /dev/null +++ b/tfweb/src/app.d.ts @@ -0,0 +1,12 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface Platform {} + } +} + +export {}; diff --git a/tfweb/src/app.html b/tfweb/src/app.html new file mode 100644 index 0000000..181852f --- /dev/null +++ b/tfweb/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/tfweb/src/components/Badge.svelte b/tfweb/src/components/Badge.svelte new file mode 100644 index 0000000..5b0c6d4 --- /dev/null +++ b/tfweb/src/components/Badge.svelte @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/tfweb/src/components/Header.svelte b/tfweb/src/components/Header.svelte new file mode 100644 index 0000000..2d35b82 --- /dev/null +++ b/tfweb/src/components/Header.svelte @@ -0,0 +1,93 @@ + + +
+ +
\ No newline at end of file diff --git a/tfweb/src/components/Theme.svelte b/tfweb/src/components/Theme.svelte new file mode 100644 index 0000000..429466f --- /dev/null +++ b/tfweb/src/components/Theme.svelte @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/tfweb/src/i18n/en.json b/tfweb/src/i18n/en.json new file mode 100644 index 0000000..115fc8f --- /dev/null +++ b/tfweb/src/i18n/en.json @@ -0,0 +1,13 @@ +{ + "common": { + "localeName": "English", + "appName": "trifid", + "flag": "gb", + "selected": "selected" + }, + "header": { + "lightMode": "Light mode", + "darkMode": "Dark mode", + "changeLang": "Change language" + } +} \ No newline at end of file diff --git a/tfweb/src/i18n/jp.json b/tfweb/src/i18n/jp.json new file mode 100644 index 0000000..adcd974 --- /dev/null +++ b/tfweb/src/i18n/jp.json @@ -0,0 +1,13 @@ +{ + "common": { + "localeName": "日本語", + "appName": "trifid", + "flag": "jp", + "selected": "選択済み" + }, + "header": { + "lightMode": "ライトモード", + "darkMode": "ダークモード", + "changeLang": "言語の変更" + } +} \ No newline at end of file diff --git a/tfweb/src/i18n/nl.json b/tfweb/src/i18n/nl.json new file mode 100644 index 0000000..0bf95f0 --- /dev/null +++ b/tfweb/src/i18n/nl.json @@ -0,0 +1,13 @@ +{ + "common": { + "localeName": "Nederlands", + "appName": "trifid", + "flag": "nl", + "selected": "Geselecteerd" + }, + "header": { + "lightMode": "Lichtmodus", + "darkMode": "Donkere modus", + "changeLang": "Taal wijzigen" + } +} \ No newline at end of file diff --git a/tfweb/src/routes/+layout.svelte b/tfweb/src/routes/+layout.svelte new file mode 100644 index 0000000..51e9eca --- /dev/null +++ b/tfweb/src/routes/+layout.svelte @@ -0,0 +1,11 @@ + + + + +
+ diff --git a/tfweb/src/routes/auth/login/+page.svelte b/tfweb/src/routes/auth/login/+page.svelte new file mode 100644 index 0000000..c90b2b3 --- /dev/null +++ b/tfweb/src/routes/auth/login/+page.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/tfweb/src/scripts/PersistentStore.ts b/tfweb/src/scripts/PersistentStore.ts new file mode 100644 index 0000000..7e04695 --- /dev/null +++ b/tfweb/src/scripts/PersistentStore.ts @@ -0,0 +1,11 @@ +import type { Writable } from "svelte/store"; +import {writable} from "svelte/store"; +import {browser} from "$app/environment"; + +export function persist(name: string, def_val = ""): Writable { + const store = writable(browser && localStorage.getItem(name) || def_val); + store.subscribe((value: any) => { + if (browser) return (localStorage.setItem(name, value)); + }); + return store; +} \ No newline at end of file diff --git a/tfweb/src/scripts/i18n.ts b/tfweb/src/scripts/i18n.ts new file mode 100644 index 0000000..c0a82d7 --- /dev/null +++ b/tfweb/src/scripts/i18n.ts @@ -0,0 +1,50 @@ +import {locale} from "../stores/LocaleStore"; +import {get} from "svelte/store"; + +import en from "../i18n/en.json"; +import jp from "../i18n/jp.json"; +import nl from "../i18n/nl.json"; +import {Logger, logSetup} from "./logger"; + +logSetup(); +const logger = new Logger("i18n"); + +export const locales: any = { + "en": en, + "jp": jp, + "nl": nl +} + +export function getCurrentLocale(): string { + return get(locale); +} + +export function setLocale(newLocale: string) { + logger.info(`Setting locale to ${newLocale}`); + if (!(newLocale in locales)) { + logger.error(`Locale ${newLocale} does not exist`); + return false; + } + locale.set(newLocale); + return true; +} + +export function t(query: string, locale = ""): string { + let val: any = locales[locale === "" ? getCurrentLocale() : locale]; + const spl: Array = query.split('.'); + for (let i = 0; i < spl.length; i++) { + const item = spl[i]; + if (item in val) { + val = val[item]; + } else { + logger.info(`missing locale string ${query}`); + val = "missing: " + query; + break; + } + } + if (typeof val === "object") { + logger.info(`query string ${query} is not a message`); + return "missing: " + query; + } + return val; +} \ No newline at end of file diff --git a/tfweb/src/scripts/logger.ts b/tfweb/src/scripts/logger.ts new file mode 100644 index 0000000..97c6361 --- /dev/null +++ b/tfweb/src/scripts/logger.ts @@ -0,0 +1,118 @@ +// LOG LEVELS: +// 0: Fatal +// 1: Error +// 2: Warn +// 3: Info +// 4: Debug +// Logs are written in-memory and logged to console if logLevel > showLogLevel +let loglevel = 0; + +export const LEVEL_FATAL = 0; +export const LEVEL_ERROR = 1; +export const LEVEL_WARN = 2; +export const LEVEL_INFO = 3; +export const LEVEL_DEBUG = 4; + +interface LogLine { + level: number, + module: string, + message: string, + timestamp: number, + deltaStart: number, + deltaLast: number +} + +const debugLog: Array = []; +let timestampStart: number; +let deltaTimestamp: number; +let logger: Logger; +let loggerSetup = false; + +export function logSetup() { + if (loggerSetup) return; + loggerSetup = true; + timestampStart = Date.now(); + deltaTimestamp = Date.now(); + logger = new Logger("Logger.ts"); + consoleLogLevel(LEVEL_INFO); + logger.info("Logger setup complete"); +} + +function log(level: number, module: string, message: string) { + const log = { + level: level, + module: module, + message: message, + timestamp: Date.now(), + deltaStart: Date.now() - timestampStart, + deltaLast: Date.now() - deltaTimestamp + }; + deltaTimestamp = Date.now(); + + debugLog.push(log); + + consoleLogHandler(log); +} + +function consoleLogHandler(log: LogLine) { + if (import.meta.env.SSR) return; // no logging in ssr + if (log.level <= loglevel) { + let textstyle = ""; + switch (log.level) { + case 0: + textstyle = "color:red;font-weight:bold;"; + break; + case 1: + textstyle = "color:red;"; + break; + case 2: + textstyle = "color:yellow;"; + break; + case 3: + textstyle = ""; + break; + case 4: + textstyle = "color:gray;"; + break; + } + console.log(`%c${new Date(log.timestamp).toISOString()} ${(log.deltaStart / 1000).toFixed(3)}Σ ${(log.deltaLast / 1000).toFixed(3)}Δ\n%c[${log.module}]%c ${log.message}`, "color:gray", "color:#8c188c", textstyle); + } +} + +export function consoleLogLevel(level: number) { + loglevel = level; +} + +export function consoleLogDump() { + for (let i = 0; i < debugLog.length; i++) { + consoleLogHandler(debugLog[i]); + } +} + +export class Logger { + private name: string; + + constructor(name: string) { + this.name = name; + } + + fatal(message: any) { + log(LEVEL_FATAL, this.name, message) + } + + error(message: any) { + log(LEVEL_ERROR, this.name, message) + } + + warn(message: any) { + log(LEVEL_WARN, this.name, message) + } + + info(message: any) { + log(LEVEL_INFO, this.name, message) + } + + debug(message: any) { + log(LEVEL_DEBUG, this.name, message) + } +} \ No newline at end of file diff --git a/tfweb/src/stores/LocaleStore.ts b/tfweb/src/stores/LocaleStore.ts new file mode 100644 index 0000000..c071378 --- /dev/null +++ b/tfweb/src/stores/LocaleStore.ts @@ -0,0 +1,3 @@ +import { persist } from "../scripts/PersistentStore"; + +export const locale = persist("lang", "en"); \ No newline at end of file diff --git a/tfweb/src/stores/ThemeStore.ts b/tfweb/src/stores/ThemeStore.ts new file mode 100644 index 0000000..1bdb296 --- /dev/null +++ b/tfweb/src/stores/ThemeStore.ts @@ -0,0 +1,3 @@ +import { persist } from "../scripts/PersistentStore"; + +export const theme = persist("theme", "light"); \ No newline at end of file diff --git a/tfweb/static/favicon.png b/tfweb/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH