Migrate to sveltekit #26

Merged
leomurca merged 36 commits from migrate-to-sveltekit into development 2025-06-04 21:41:44 +00:00
28 changed files with 552 additions and 28 deletions
Showing only changes of commit c573d8c2c6 - Show all commits

View file

@ -3,13 +3,19 @@ export { matchers } from './matchers.js';
export const nodes = [ export const nodes = [
() => import('./nodes/0'), () => import('./nodes/0'),
() => import('./nodes/1'), () => import('./nodes/1'),
() => import('./nodes/2') () => import('./nodes/2'),
() => import('./nodes/3'),
() => import('./nodes/4'),
() => import('./nodes/5')
]; ];
export const server_loads = []; export const server_loads = [];
export const dictionary = { export const dictionary = {
"/": [2] "/": [2],
"/about": [3],
"/donate": [4],
"/viewer": [5]
}; };
export const hooks = { export const hooks = {

View file

@ -1 +1,3 @@
export { default as component } from "../../../../node_modules/@sveltejs/kit/src/runtime/components/svelte-5/layout.svelte"; import * as universal from "../../../../src/routes/+layout.js";
export { universal };
export { default as component } from "../../../../src/routes/+layout.svelte";

View file

@ -0,0 +1 @@
export { default as component } from "../../../../src/routes/about/+page.svelte";

View file

@ -0,0 +1 @@
export { default as component } from "../../../../src/routes/donate/+page.svelte";

View file

@ -0,0 +1 @@
export { default as component } from "../../../../src/routes/viewer/+page.svelte";

View file

@ -18,10 +18,10 @@ export const options = {
root, root,
service_worker: false, service_worker: false,
templates: { templates: {
app: ({ head, body, assets, nonce, env }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t" + head + "\n\t</head>\n\t<body data-sveltekit-preload-data=\"hover\">\n\t\t<div style=\"display: contents\">" + body + "</div>\n\t</body>\n</html>\n", app: ({ head, body, assets, nonce, env }) => "<!doctype html>\n<html lang=\"en\">\n <head>\n <style>\n :root {\n font-family: Inter, Avenir, Helvetica, Arial, sans-serif;\n font-size: 16px;\n line-height: 24px;\n font-weight: 400;\n font-synthesis: none;\n text-rendering: optimizeLegibility;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n -webkit-text-size-adjust: 100%;\n }\n\n * {\n box-sizing: border-box;\n }\n\n body {\n display: flex;\n justify-content: center;\n flex-direction: column;\n margin: 0;\n width: 100%;\n height: 100%;\n }\n\n #app {\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n background-color: #f2f6f5;\n z-index: 10;\n }\n\n input[type='submit'] {\n width: 100%;\n font-size: 20px;\n margin-top: 20px;\n background-color: #05345f;\n font-weight: 700;\n color: white;\n padding: 10px;\n -webkit-appearance: none;\n border-radius: 0;\n }\n\n input[type='submit']:hover {\n cursor: pointer;\n background-color: black;\n color: white;\n }\n\n body a {\n text-decoration: none;\n color: #06345f;\n border-bottom: 3px solid #06345f;\n }\n\n body a:hover {\n background-color: #06345f;\n color: #ffffff;\n }\n\n :is(h1, h2, h3, h4, h5, h6) {\n color: #06345f;\n }\n\n strong {\n color: #06345f;\n }\n\n ul li::marker {\n color: #06345f;\n }\n </style>\n <meta charset=\"utf-8\" />\n <link rel=\"icon\" href=\"" + assets + "/favicon.png\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n " + head + "\n </head>\n <body data-sveltekit-preload-data=\"hover\">\n <div style=\"display: contents\">" + body + "</div>\n </body>\n</html>\n",
error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n" error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
}, },
version_hash: "au0v7i" version_hash: "lnkeyd"
}; };
export async function get_hooks() { export async function get_hooks() {

View file

@ -1,3 +1,15 @@
{ {
"/": [] "/": [
"src/routes/+layout.js",
"src/routes/+layout.js"
],
"/about": [
"src/routes/+layout.js"
],
"/donate": [
"src/routes/+layout.js"
],
"/viewer": [
"src/routes/+layout.js"
]
} }

View file

@ -12,7 +12,7 @@ type EnsureDefined<T> = T extends null | undefined ? {} : T;
type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never; type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
export type Snapshot<T = any> = Kit.Snapshot<T>; export type Snapshot<T = any> = Kit.Snapshot<T>;
type PageParentData = EnsureDefined<LayoutData>; type PageParentData = EnsureDefined<LayoutData>;
type LayoutRouteId = RouteId | "/" | null type LayoutRouteId = RouteId | "/" | "/about" | "/donate" | "/viewer" | null
type LayoutParams = RouteParams & { } type LayoutParams = RouteParams & { }
type LayoutParentData = EnsureDefined<{}>; type LayoutParentData = EnsureDefined<{}>;
@ -20,5 +20,7 @@ export type PageServerData = null;
export type PageData = Expand<PageParentData>; export type PageData = Expand<PageParentData>;
export type PageProps = { data: PageData } export type PageProps = { data: PageData }
export type LayoutServerData = null; export type LayoutServerData = null;
export type LayoutData = Expand<LayoutParentData>; export type LayoutLoad<OutputData extends OutputDataShape<LayoutParentData> = OutputDataShape<LayoutParentData>> = Kit.Load<LayoutParams, LayoutServerData, LayoutParentData, OutputData, LayoutRouteId>;
export type LayoutLoadEvent = Parameters<LayoutLoad>[0];
export type LayoutData = Expand<Omit<LayoutParentData, keyof Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.js').load>>>> & OptionalUnion<EnsureDefined<Kit.LoadProperties<Awaited<ReturnType<typeof import('./proxy+layout.js').load>>>>>>;
export type LayoutProps = { data: LayoutData; children: import("svelte").Snippet } export type LayoutProps = { data: LayoutData; children: import("svelte").Snippet }

View file

@ -0,0 +1,18 @@
import type * as Kit from '@sveltejs/kit';
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// @ts-ignore
type MatcherParam<M> = M extends (param : string) => param is infer U ? U extends string ? U : string : string;
type RouteParams = { };
type RouteId = '/about';
type MaybeWithVoid<T> = {} extends T ? T | void : T;
export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];
type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>
type EnsureDefined<T> = T extends null | undefined ? {} : T;
type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
export type Snapshot<T = any> = Kit.Snapshot<T>;
type PageParentData = EnsureDefined<import('../$types.js').LayoutData>;
export type PageServerData = null;
export type PageData = Expand<PageParentData>;
export type PageProps = { data: PageData }

View file

@ -0,0 +1,18 @@
import type * as Kit from '@sveltejs/kit';
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// @ts-ignore
type MatcherParam<M> = M extends (param : string) => param is infer U ? U extends string ? U : string : string;
type RouteParams = { };
type RouteId = '/donate';
type MaybeWithVoid<T> = {} extends T ? T | void : T;
export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];
type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>
type EnsureDefined<T> = T extends null | undefined ? {} : T;
type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
export type Snapshot<T = any> = Kit.Snapshot<T>;
type PageParentData = EnsureDefined<import('../$types.js').LayoutData>;
export type PageServerData = null;
export type PageData = Expand<PageParentData>;
export type PageProps = { data: PageData }

View file

@ -0,0 +1,17 @@
// @ts-nocheck
import { loadTranslations } from '$lib/translations';
/** */
export const load = async () => {
const initLocale = primaryLanguage(navigator.language) || 'en';
// TODO: Fix the undefined location issue
await loadTranslations(initLocale);
return {};
};
const primaryLanguage = (/** @type {string} */ locale) => {
if (!locale) return '';
return locale.split('-')[0];
};

View file

@ -0,0 +1,18 @@
import type * as Kit from '@sveltejs/kit';
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// @ts-ignore
type MatcherParam<M> = M extends (param : string) => param is infer U ? U extends string ? U : string : string;
type RouteParams = { };
type RouteId = '/viewer';
type MaybeWithVoid<T> = {} extends T ? T | void : T;
export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];
type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>
type EnsureDefined<T> = T extends null | undefined ? {} : T;
type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
export type Snapshot<T = any> = Kit.Snapshot<T>;
type PageParentData = EnsureDefined<import('../$types.js').LayoutData>;
export type PageServerData = null;
export type PageData = Expand<PageParentData>;
export type PageProps = { data: PageData }

53
package-lock.json generated
View file

@ -7,6 +7,9 @@
"": { "": {
"name": "embroidery-viewer", "name": "embroidery-viewer",
"version": "0.0.1", "version": "0.0.1",
"dependencies": {
"sveltekit-i18n": "^2.4.2"
},
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.2.5", "@eslint/compat": "^1.2.5",
"@eslint/js": "^9.18.0", "@eslint/js": "^9.18.0",
@ -29,7 +32,6 @@
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/gen-mapping": "^0.3.5",
@ -706,7 +708,6 @@
"version": "0.3.8", "version": "0.3.8",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/set-array": "^1.2.1", "@jridgewell/set-array": "^1.2.1",
@ -721,7 +722,6 @@
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
@ -731,7 +731,6 @@
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
@ -741,14 +740,12 @@
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@jridgewell/trace-mapping": { "node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25", "version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/resolve-uri": "^3.1.0",
@ -1046,7 +1043,6 @@
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
"integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"acorn": "^8.9.0" "acorn": "^8.9.0"
@ -1134,6 +1130,21 @@
"vite": "^6.0.0" "vite": "^6.0.0"
} }
}, },
"node_modules/@sveltekit-i18n/base": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/@sveltekit-i18n/base/-/base-1.3.7.tgz",
"integrity": "sha512-kg1kql1/ro/lIudwFiWrv949Q07gmweln87tflUZR51MNdXXzK4fiJQv5Mw50K/CdQ5BOk/dJ0WOH2vOtBI6yw==",
"license": "MIT",
"peerDependencies": {
"svelte": ">=3.49.0"
}
},
"node_modules/@sveltekit-i18n/parser-default": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@sveltekit-i18n/parser-default/-/parser-default-1.1.1.tgz",
"integrity": "sha512-/gtzLlqm/sox7EoPKD56BxGZktK/syGc79EbJAPWY5KVitQD9SM0TP8yJCqDxTVPk7Lk0WJhrBGUE2Nn0f5M1w==",
"license": "MIT"
},
"node_modules/@types/cookie": { "node_modules/@types/cookie": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
@ -1145,7 +1156,6 @@
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/json-schema": { "node_modules/@types/json-schema": {
@ -1159,7 +1169,6 @@
"version": "8.14.1", "version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
@ -1222,7 +1231,6 @@
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
"dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -1232,7 +1240,6 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
"dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -1303,7 +1310,6 @@
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
@ -1615,7 +1621,6 @@
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
"integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/espree": { "node_modules/espree": {
@ -1653,7 +1658,6 @@
"version": "1.4.6", "version": "1.4.6",
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz", "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz",
"integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15" "@jridgewell/sourcemap-codec": "^1.4.15"
@ -1894,7 +1898,6 @@
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
"integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/estree": "^1.0.6" "@types/estree": "^1.0.6"
@ -1996,7 +1999,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/locate-path": { "node_modules/locate-path": {
@ -2026,7 +2028,6 @@
"version": "0.30.17", "version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0" "@jridgewell/sourcemap-codec": "^1.5.0"
@ -2560,7 +2561,6 @@
"version": "5.33.13", "version": "5.33.13",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.33.13.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.33.13.tgz",
"integrity": "sha512-uT3BAPpHGaJqpOgdwJwIK7P4JkBkSS0vylbaRXxQjt1gr+DZ9BiPkhmbZw3ql8LJofUyz5XyrzzQDgQQdfP86Q==", "integrity": "sha512-uT3BAPpHGaJqpOgdwJwIK7P4JkBkSS0vylbaRXxQjt1gr+DZ9BiPkhmbZw3ql8LJofUyz5XyrzzQDgQQdfP86Q==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.3.0", "@ampproject/remapping": "^2.3.0",
@ -2635,6 +2635,22 @@
} }
} }
}, },
"node_modules/sveltekit-i18n": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/sveltekit-i18n/-/sveltekit-i18n-2.4.2.tgz",
"integrity": "sha512-hjRWn4V4DBL8JQKJoJa3MRvn6d32Zo+rWkoSP5bsQ/XIAguPdQUZJ8LMe6Nc1rST8WEVdu9+vZI3aFdKYGR3+Q==",
"license": "MIT",
"workspaces": [
"./examples/*/"
],
"dependencies": {
"@sveltekit-i18n/base": "~1.3.0",
"@sveltekit-i18n/parser-default": "~1.1.0"
},
"peerDependencies": {
"svelte": ">=3.49.0"
}
},
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.14", "version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
@ -2858,7 +2874,6 @@
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
"integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
"dev": true,
"license": "MIT" "license": "MIT"
} }
} }

View file

@ -29,5 +29,8 @@
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
"typescript": "^5.0.0", "typescript": "^5.0.0",
"vite": "^6.2.6" "vite": "^6.2.6"
},
"dependencies": {
"sveltekit-i18n": "^2.4.2"
} }
} }

View file

@ -1 +0,0 @@
<h1>Hello world!</h1>

View file

@ -1,6 +1,82 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<style>
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
flex-direction: column;
margin: 0;
width: 100%;
height: 100%;
}
#app {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
background-color: #f2f6f5;
z-index: 10;
}
input[type='submit'] {
width: 100%;
font-size: 20px;
margin-top: 20px;
background-color: #05345f;
font-weight: 700;
color: white;
padding: 10px;
-webkit-appearance: none;
border-radius: 0;
}
input[type='submit']:hover {
cursor: pointer;
background-color: black;
color: white;
}
body a {
text-decoration: none;
color: #06345f;
border-bottom: 3px solid #06345f;
}
body a:hover {
background-color: #06345f;
color: #ffffff;
}
:is(h1, h2, h3, h4, h5, h6) {
color: #06345f;
}
strong {
color: #06345f;
}
ul li::marker {
color: #06345f;
}
</style>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />

BIN
src/lib/assets/logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,203 @@
<script>
import { t, locale, locales } from '$lib/translations';
import logo from '$lib/assets/logo.webp';
import MediaQuery from './MediaQuery.svelte';
const configsFor = (/** @type {boolean} */ matches) => {
return matches
? { src: logo, width: 150, height: 70 } // mobile
: { src: logo, width: 150, height: 100 }; // desktop
};
const onSwitchToOppositeLang = () => {
$locale = $locale === 'en' ? 'pt' : 'en';
};
let isMenuOpen = false;
</script>
<header>
<div class="logo">
<MediaQuery query="(max-width: 768px)" let:matches>
{@const configs = configsFor(matches)}
<a href="/">
<img
src={configs.src}
alt="Embroidery viewer logo"
width={configs.width}
height={configs.height}
/>
</a>
</MediaQuery>
</div>
<div class="nav-container">
<MediaQuery query="(max-width: 768px)" let:matches>
<slot let-matches>
{#if matches}
<button class="hamburger" on:click={() => (isMenuOpen = !isMenuOpen)}>
{#if isMenuOpen}x{:else}{/if}
</button>
{/if}
</slot>
</MediaQuery>
<nav class:is-open={isMenuOpen}>
<ul>
<li>
<a href="/">{$t('header.homeNav')}</a>
</li>
<li>
<a href="/viewer">{$t('header.viewerNav')}</a>
</li>
<li>
<a href="/about">{$t('header.aboutNav')}</a>
</li>
<li>
<a href="/donate">{$t('header.donateNav')}</a>
</li>
</ul>
</nav>
<a
class="common-switch {$locale === 'en'
? 'portuguese-switch'
: 'english-switch'}"
href="#"
on:click|preventDefault={onSwitchToOppositeLang}
>
<div style="display: flex; width: fit-content;">
<span style="font-size: 20px;">{$t('header.languageSwitch')}</span>
</div>
</a>
</div>
</header>
<style>
header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 100px;
background-color: #f8f9fa;
border-bottom: 1px solid #ddd;
width: 100%;
}
.logo img {
height: auto;
max-height: 60px;
}
.logo a {
border-bottom: none;
}
.logo a:hover {
background: transparent;
}
.nav-container {
display: flex;
gap: 20px;
align-items: center;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
gap: 20px;
}
nav ul li {
display: flex;
font-weight: bold;
}
.hamburger {
background: none;
border: none;
font-size: 35px;
width: 35px;
padding: 0;
margin: 0;
cursor: pointer;
display: none;
}
.common-switch {
width: fit-content;
}
.portuguese-switch {
color: #0c8f27;
border-bottom: 3px solid #0c8f27 !important;
fill: #0c8f27 !important;
}
.portuguese-switch:hover {
background: #0c8f27;
color: #ffffff;
fill: #ffffff !important;
}
.english-switch {
color: #be0a2f;
border-bottom: 3px solid #be0a2f;
width: fit-content;
fill: #be0a2f !important;
}
.english-switch:hover {
background: #be0a2f;
color: #ffffff;
fill: #ffffff !important;
}
@media (max-width: 768px) {
header {
padding: 10px 20px;
}
.hamburger {
display: block;
width: 35px;
}
nav {
display: none;
flex-direction: column;
gap: 10px;
background-color: #f8f9fa;
position: absolute;
top: 60px;
right: 0;
border: 1px solid #ddd;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
nav.is-open {
display: inline-block;
margin-top: 25px;
width: 100%;
}
nav ul {
flex-direction: column;
gap: 0px;
width: 100%;
}
nav ul li {
text-align: center;
width: 100%;
}
nav ul li a {
display: inline-block;
width: 100%;
padding: 10px;
border-bottom: none;
}
}
</style>

View file

@ -0,0 +1,48 @@
<script>
import { onMount } from 'svelte';
export let query;
/**
* @type {MediaQueryList}
*/
let mql;
/**
* @type {((this: MediaQueryList, ev: MediaQueryListEvent) => any) | null}
*/
let mqlListener;
let wasMounted = false;
let matches = false;
onMount(() => {
wasMounted = true;
return () => {
removeActiveListener();
};
});
$: {
if (wasMounted) {
removeActiveListener();
addNewListener(query);
}
}
/**
* @param {string} query
*/
function addNewListener(query) {
mql = window.matchMedia(query);
mqlListener = (v) => (matches = v.matches);
mql.addListener(mqlListener);
matches = mql.matches;
}
function removeActiveListener() {
if (mql && mqlListener) {
mql.removeListener(mqlListener);
}
}
</script>
<slot {matches} />

View file

@ -0,0 +1,7 @@
{
"languageSwitch": "🇧🇷",
"homeNav": "🏠 Home",
"aboutNav": " About",
"viewerNav": "🧵 Viewer",
"donateNav": "💖 Donate"
}

View file

@ -0,0 +1,41 @@
import i18n from 'sveltekit-i18n';
import lang from './lang.json';
/** @type {import('sveltekit-i18n').Config} */
const config = {
translations: {
en: { lang },
pt: { lang },
},
loaders: [
{
locale: 'en',
key: 'header',
loader: async () => (await import('./en/header.json')).default,
},
{
locale: 'pt',
key: 'header',
loader: async () => (await import('./pt/header.json')).default,
},
],
};
export const { t, locale, locales, loading, loadTranslations } = new i18n(
config,
);
// Save to localStorage on change
locale.subscribe(($locale) => {
if (typeof localStorage !== 'undefined') {
localStorage.setItem('locale', $locale);
}
});
// Load from localStorage on initialization
if (typeof localStorage !== 'undefined') {
const savedLocale = localStorage.getItem('locale');
if (savedLocale && savedLocale !== 'null') {
locale.set(savedLocale);
}
}

View file

@ -0,0 +1,4 @@
{
"en": "English",
"pt": "Português"
}

View file

@ -0,0 +1,7 @@
{
"languageSwitch": "🇺🇸",
"homeNav": "🏠 Página Inicial",
"aboutNav": " Sobre",
"viewerNav": "🧵 Visualizador",
"donateNav": "💖 Doe"
}

16
src/routes/+layout.js Normal file
View file

@ -0,0 +1,16 @@
import { loadTranslations } from '$lib/translations';
/** @type {import('@sveltejs/kit').Load} */
export const load = async () => {
const initLocale = primaryLanguage(navigator.language) || 'en';
// TODO: Fix the undefined location issue
await loadTranslations(initLocale);
return {};
};
const primaryLanguage = (/** @type {string} */ locale) => {
if (!locale) return '';
return locale.split('-')[0];
};

View file

@ -0,0 +1,6 @@
<script>
import Header from '$lib/components/Header.svelte';
</script>
<Header />
<slot />

View file

@ -0,0 +1 @@
<h1>About</h1>

View file

@ -0,0 +1 @@
<h1>Donate</h1>

View file

@ -0,0 +1 @@
<h1>Viewer</h1>