stuff
This commit is contained in:
@@ -3,13 +3,17 @@ export { matchers } from './matchers.js';
|
||||
export const nodes = [
|
||||
() => import('./nodes/0'),
|
||||
() => import('./nodes/1'),
|
||||
() => import('./nodes/2')
|
||||
() => import('./nodes/2'),
|
||||
() => import('./nodes/3'),
|
||||
() => import('./nodes/4')
|
||||
];
|
||||
|
||||
export const server_loads = [];
|
||||
|
||||
export const dictionary = {
|
||||
"/": [2]
|
||||
"/": [2],
|
||||
"/history": [3],
|
||||
"/settings": [4]
|
||||
};
|
||||
|
||||
export const hooks = {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default as component } from "../../../../src/routes/history/+page.svelte";
|
||||
@@ -0,0 +1 @@
|
||||
export { default as component } from "../../../../src/routes/settings/+page.svelte";
|
||||
@@ -22,10 +22,10 @@ export const options = {
|
||||
service_worker_options: undefined,
|
||||
server_error_boundaries: false,
|
||||
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<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t<meta name=\"text-scale\" content=\"scale\" />\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\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t<meta name=\"text-scale\" content=\"scale\" />\n\t\t<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n\t\t<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n\t\t<link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Outfit:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n\t\t" + head + "\n\t</head>\n\t<body data-sveltekit-preload-data=\"hover\" class=\"bg-black text-slate-200 font-sans antialiased selection:bg-neon-primary/30 selection:text-neon-primary\">\n\t\t<div style=\"display: contents\">" + body + "</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: "7g1qkw"
|
||||
version_hash: "1jkuefu"
|
||||
};
|
||||
|
||||
export async function get_hooks() {
|
||||
|
||||
Vendored
+5
-3
@@ -29,14 +29,16 @@ declare module "$app/types" {
|
||||
type MatcherParam<M> = M extends (param : string) => param is (infer U extends string) ? U : string;
|
||||
|
||||
export interface AppTypes {
|
||||
RouteId(): "/";
|
||||
RouteId(): "/" | "/history" | "/settings";
|
||||
RouteParams(): {
|
||||
|
||||
};
|
||||
LayoutParams(): {
|
||||
"/": Record<string, never>
|
||||
"/": Record<string, never>;
|
||||
"/history": Record<string, never>;
|
||||
"/settings": Record<string, never>
|
||||
};
|
||||
Pathname(): "/";
|
||||
Pathname(): "/" | "/history" | "/settings";
|
||||
ResolvedPathname(): `${"" | `/${string}`}${ReturnType<AppTypes['Pathname']>}`;
|
||||
Asset(): "/robots.txt" | string & {};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"/": []
|
||||
"/": [],
|
||||
"/history": [],
|
||||
"/settings": []
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,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;
|
||||
export type Snapshot<T = any> = Kit.Snapshot<T>;
|
||||
type PageParentData = EnsureDefined<LayoutData>;
|
||||
type LayoutRouteId = RouteId | "/" | null
|
||||
type LayoutRouteId = RouteId | "/" | "/history" | "/settings" | null
|
||||
type LayoutParams = RouteParams & { }
|
||||
type LayoutParentData = EnsureDefined<{}>;
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type * as Kit from '@sveltejs/kit';
|
||||
|
||||
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
|
||||
type MatcherParam<M> = M extends (param : string) => param is (infer U extends string) ? U : string;
|
||||
type RouteParams = { };
|
||||
type RouteId = '/history';
|
||||
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 = { params: RouteParams; data: PageData }
|
||||
@@ -0,0 +1,17 @@
|
||||
import type * as Kit from '@sveltejs/kit';
|
||||
|
||||
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
|
||||
type MatcherParam<M> = M extends (param : string) => param is (infer U extends string) ? U : string;
|
||||
type RouteParams = { };
|
||||
type RouteId = '/settings';
|
||||
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 = { params: RouteParams; data: PageData }
|
||||
@@ -6,6 +6,7 @@
|
||||
"name": "bitcamp-2026",
|
||||
"dependencies": {
|
||||
"@auth0/auth0-spa-js": "^2.19.0",
|
||||
"maplibre-gl": "^5.0.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/svelte": "^5.2.1",
|
||||
@@ -235,6 +236,26 @@
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/[email protected]", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@mapbox/jsonlint-lines-primitives": ["@mapbox/[email protected]", "", {}, "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ=="],
|
||||
|
||||
"@mapbox/point-geometry": ["@mapbox/[email protected]", "", {}, "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ=="],
|
||||
|
||||
"@mapbox/tiny-sdf": ["@mapbox/[email protected]", "", {}, "sha512-uFJhNh36BR4OCuWIEiWaEix9CA2WzT6CAIcqVjWYpnx8+QDtS+oC4QehRrx5cX4mgWs37MmKnwUejeHxVymzNg=="],
|
||||
|
||||
"@mapbox/unitbezier": ["@mapbox/[email protected]", "", {}, "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw=="],
|
||||
|
||||
"@mapbox/vector-tile": ["@mapbox/[email protected]", "", { "dependencies": { "@mapbox/point-geometry": "~1.1.0", "@types/geojson": "^7946.0.16", "pbf": "^4.0.1" } }, "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg=="],
|
||||
|
||||
"@mapbox/whoots-js": ["@mapbox/[email protected]", "", {}, "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q=="],
|
||||
|
||||
"@maplibre/geojson-vt": ["@maplibre/[email protected]", "", { "dependencies": { "kdbush": "^4.0.2" } }, "sha512-HYv3POhMRCdhP3UPPATM/hfcy6/WuVIf5FKboH8u/ZuFMTnAIcSVlq5nfOqroLokd925w2QtE7YwquFOIacwVQ=="],
|
||||
|
||||
"@maplibre/maplibre-gl-style-spec": ["@maplibre/[email protected]", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", "quickselect": "^3.0.0", "rw": "^1.3.3", "tinyqueue": "^3.0.0" }, "bin": { "gl-style-migrate": "dist/gl-style-migrate.mjs", "gl-style-validate": "dist/gl-style-validate.mjs", "gl-style-format": "dist/gl-style-format.mjs" } }, "sha512-zxa92qF96ZNojLxeAjnaRpjVCy+swoUNJvDhtpC90k7u5F0TMr4GmvNqMKvYrMoPB8d7gRSXbMG1hBbmgESIsw=="],
|
||||
|
||||
"@maplibre/mlt": ["@maplibre/[email protected]", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0" } }, "sha512-8vtfYGidr1rNkv5IwIoU2lfe3Oy+Wa8HluzQYcQi9cveU9K3pweAal/poQj4GJ0K/EW4bTQp2wVAs09g2yDRZg=="],
|
||||
|
||||
"@maplibre/vt-pbf": ["@maplibre/[email protected]", "", { "dependencies": { "@mapbox/point-geometry": "^1.1.0", "@mapbox/vector-tile": "^2.0.4", "@maplibre/geojson-vt": "^5.0.4", "@types/geojson": "^7946.0.16", "@types/supercluster": "^7.1.3", "pbf": "^4.0.1", "supercluster": "^8.0.1" } }, "sha512-jIvp8F5hQCcreqOOpEt42TJMUlsrEcpf/kI1T2v85YrQRV6PPXUcEXUg5karKtH6oh47XJZ4kHu56pUkOuqA7w=="],
|
||||
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/[email protected]", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ=="],
|
||||
|
||||
"@oxc-project/types": ["@oxc-project/[email protected]", "", {}, "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg=="],
|
||||
@@ -335,8 +356,12 @@
|
||||
|
||||
"@types/estree": ["@types/[email protected]", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/geojson": ["@types/[email protected]", "", {}, "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg=="],
|
||||
|
||||
"@types/resolve": ["@types/[email protected]", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
||||
|
||||
"@types/supercluster": ["@types/[email protected]", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA=="],
|
||||
|
||||
"@types/trusted-types": ["@types/[email protected]", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
|
||||
|
||||
"@vite-pwa/sveltekit": ["@vite-pwa/[email protected]", "", { "dependencies": { "kolorist": "^1.8.0", "tinyglobby": "^0.2.9" }, "peerDependencies": { "@sveltejs/kit": "^1.3.1 || ^2.0.1", "@vite-pwa/assets-generator": "^0.2.6", "vite-plugin-pwa": ">=0.21.2 <1" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-KCrADea4HajwOIJPMB/tKW/x6Xa7X2NiNoWJ5MoggNGguSFQfmtclNc9ejNuXkI7uPNLUvH2zaFmsZRrPl+Tdg=="],
|
||||
@@ -429,6 +454,8 @@
|
||||
|
||||
"dunder-proto": ["[email protected]", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"earcut": ["[email protected]", "", {}, "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ=="],
|
||||
|
||||
"ejs": ["[email protected]", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
"electron-to-chromium": ["[email protected]", "", {}, "sha512-q9n5T4BR4Xwa2cwbrwcsDJtHD/enpQ5S1xF1IAtdqf5AAgqDFmR/aakqH3ChFdqd/QXJhS3rnnXFtexU7rax6Q=="],
|
||||
@@ -495,6 +522,8 @@
|
||||
|
||||
"get-symbol-description": ["[email protected]", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="],
|
||||
|
||||
"gl-matrix": ["[email protected]", "", {}, "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ=="],
|
||||
|
||||
"glob": ["[email protected]", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="],
|
||||
|
||||
"globalthis": ["[email protected]", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
|
||||
@@ -591,12 +620,16 @@
|
||||
|
||||
"json-schema-traverse": ["[email protected]", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"json-stringify-pretty-compact": ["[email protected]", "", {}, "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q=="],
|
||||
|
||||
"json5": ["[email protected]", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
|
||||
|
||||
"jsonfile": ["[email protected]", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="],
|
||||
|
||||
"jsonpointer": ["[email protected]", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="],
|
||||
|
||||
"kdbush": ["[email protected]", "", {}, "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="],
|
||||
|
||||
"kleur": ["[email protected]", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||
|
||||
"kolorist": ["[email protected]", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="],
|
||||
@@ -639,12 +672,16 @@
|
||||
|
||||
"magic-string": ["[email protected]", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
|
||||
"maplibre-gl": ["[email protected]", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/point-geometry": "^1.1.0", "@mapbox/tiny-sdf": "^2.0.7", "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^2.0.4", "@mapbox/whoots-js": "^3.1.0", "@maplibre/geojson-vt": "^6.0.4", "@maplibre/maplibre-gl-style-spec": "^24.8.1", "@maplibre/mlt": "^1.1.8", "@maplibre/vt-pbf": "^4.3.0", "@types/geojson": "^7946.0.16", "earcut": "^3.0.2", "gl-matrix": "^3.4.4", "kdbush": "^4.0.2", "murmurhash-js": "^1.0.0", "pbf": "^4.0.1", "potpack": "^2.1.0", "quickselect": "^3.0.0", "tinyqueue": "^3.0.0" } }, "sha512-nc8YA+YSEioMZg5W0cb6Cf3wQ8aJge66dsttyBgpOArOnlmFJO1Kc5G32kYVPeUYhLpBja83T99uanmJvYAIyQ=="],
|
||||
|
||||
"math-intrinsics": ["[email protected]", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"mini-svg-data-uri": ["[email protected]", "", { "bin": { "mini-svg-data-uri": "cli.js" } }, "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg=="],
|
||||
|
||||
"minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
|
||||
|
||||
"minimist": ["[email protected]", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||
|
||||
"minipass": ["[email protected]", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
|
||||
|
||||
"mri": ["[email protected]", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
|
||||
@@ -653,6 +690,8 @@
|
||||
|
||||
"ms": ["[email protected]", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"murmurhash-js": ["[email protected]", "", {}, "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw=="],
|
||||
|
||||
"nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"node-releases": ["[email protected]", "", {}, "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg=="],
|
||||
@@ -679,6 +718,8 @@
|
||||
|
||||
"path-scurry": ["[email protected]", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
|
||||
|
||||
"pbf": ["[email protected]", "", { "dependencies": { "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA=="],
|
||||
|
||||
"picocolors": ["[email protected]", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["[email protected]", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
||||
@@ -689,10 +730,16 @@
|
||||
|
||||
"postcss-selector-parser": ["[email protected]", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="],
|
||||
|
||||
"potpack": ["[email protected]", "", {}, "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ=="],
|
||||
|
||||
"pretty-bytes": ["[email protected]", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="],
|
||||
|
||||
"protocol-buffers-schema": ["[email protected]", "", {}, "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ=="],
|
||||
|
||||
"punycode": ["[email protected]", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"quickselect": ["[email protected]", "", {}, "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="],
|
||||
|
||||
"randombytes": ["[email protected]", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="],
|
||||
|
||||
"readdirp": ["[email protected]", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
@@ -715,10 +762,14 @@
|
||||
|
||||
"resolve": ["[email protected]", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="],
|
||||
|
||||
"resolve-protobuf-schema": ["[email protected]", "", { "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ=="],
|
||||
|
||||
"rolldown": ["[email protected]", "", { "dependencies": { "@oxc-project/types": "=0.124.0", "@rolldown/pluginutils": "1.0.0-rc.15" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-x64": "1.0.0-rc.15", "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g=="],
|
||||
|
||||
"rollup": ["[email protected]", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ=="],
|
||||
|
||||
"rw": ["[email protected]", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="],
|
||||
|
||||
"sade": ["[email protected]", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
|
||||
|
||||
"safe-array-concat": ["[email protected]", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="],
|
||||
@@ -781,6 +832,8 @@
|
||||
|
||||
"strip-comments": ["[email protected]", "", {}, "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw=="],
|
||||
|
||||
"supercluster": ["[email protected]", "", { "dependencies": { "kdbush": "^4.0.2" } }, "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ=="],
|
||||
|
||||
"supports-preserve-symlinks-flag": ["[email protected]", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||
|
||||
"svelte": ["[email protected]", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.4", "esm-env": "^1.2.1", "esrap": "^2.2.4", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-dS1N+i3bA1v+c4UDb750MlN5vCO82G6vxh8HeTsPsTdJ1BLsN1zxSyDlIdBBqUjqZ/BxEwM8UrFf98aaoVnZFQ=="],
|
||||
@@ -799,6 +852,8 @@
|
||||
|
||||
"tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
|
||||
|
||||
"tinyqueue": ["[email protected]", "", {}, "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="],
|
||||
|
||||
"totalist": ["[email protected]", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="],
|
||||
|
||||
"tr46": ["[email protected]", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
|
||||
@@ -893,6 +948,8 @@
|
||||
|
||||
"zimmerframe": ["[email protected]", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="],
|
||||
|
||||
"@maplibre/vt-pbf/@maplibre/geojson-vt": ["@maplibre/[email protected]", "", {}, "sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ=="],
|
||||
|
||||
"@rollup/plugin-node-resolve/@rollup/pluginutils": ["@rollup/[email protected]", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||
|
||||
"@rollup/plugin-replace/magic-string": ["[email protected]", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@auth0/auth0-spa-js": "^2.19.0"
|
||||
"@auth0/auth0-spa-js": "^2.19.0",
|
||||
"maplibre-gl": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/svelte": "^5.2.1",
|
||||
|
||||
@@ -4,9 +4,12 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="text-scale" content="scale" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<body data-sveltekit-preload-data="hover" class="bg-black text-slate-200 font-sans antialiased selection:bg-neon-primary/30 selection:text-neon-primary">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
|
||||
let isOpen = $state(false);
|
||||
|
||||
const mockAlerts = [
|
||||
{ id: 1, loc: 'McKeldin 2nd Floor', level: 78, time: '2 mins ago' },
|
||||
{ id: 2, loc: 'ESJ Atrium', level: 82, time: '15 mins ago' }
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="relative">
|
||||
<!-- Notification Bell -->
|
||||
<button onclick={() => isOpen = !isOpen} class="relative w-12 h-12 glass-panel flex items-center justify-center rounded-xl border border-white/10 hover:bg-white/10 transition-colors group {isOpen ? 'bg-white/10 ring-1 ring-neon-alert' : ''}">
|
||||
<Icon icon="mdi:bell-outline" class="text-2xl text-slate-300 group-hover:text-white" />
|
||||
<!-- Badge -->
|
||||
{#if mockAlerts.length > 0}
|
||||
<span class="absolute top-2 right-2 w-2.5 h-2.5 bg-neon-alert rounded-full shadow-[0_0_8px_rgba(255,7,58,0.8)] animate-pulse border border-slate-900"></span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<!-- Dropdown Panel -->
|
||||
{#if isOpen}
|
||||
<div class="absolute top-14 left-0 w-80 glass-panel rounded-2xl shadow-2xl border border-white/10 overflow-hidden z-30 animate-in fade-in slide-in-from-top-2">
|
||||
<div class="px-4 py-3 border-b border-white/10 bg-black/40 flex justify-between items-center">
|
||||
<h3 class="font-display font-medium text-white text-sm">Active Noise Alerts</h3>
|
||||
<span class="text-xs text-slate-400 bg-white/5 py-0.5 px-2 rounded-full">{mockAlerts.length} New</span>
|
||||
</div>
|
||||
|
||||
<div class="max-h-64 overflow-y-auto">
|
||||
{#each mockAlerts as alert}
|
||||
<button class="w-full text-left p-4 border-b border-white/5 hover:bg-white/5 transition-colors flex items-start gap-3">
|
||||
<Icon icon="mdi:alert-rhombus-outline" class="text-neon-alert text-xl mt-0.5" />
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium text-red-200">Spike Detected: {alert.level} dB</p>
|
||||
<p class="text-xs text-red-400/80 mt-1">{alert.loc}</p>
|
||||
</div>
|
||||
<p class="text-[10px] text-slate-500 font-mono mt-1">{alert.time}</p>
|
||||
</button>
|
||||
{/each}
|
||||
|
||||
{#if mockAlerts.length === 0}
|
||||
<div class="p-6 text-center text-slate-500">
|
||||
<Icon icon="mdi:check-circle-outline" class="text-3xl text-neon-primary mx-auto mb-2 opacity-50" />
|
||||
<p class="text-sm">Campus is quiet right now.</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1,124 @@
|
||||
<script lang="ts">
|
||||
import { onMount, untrack } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { mapState, UMD_LOCATIONS } from '$lib/states/map.svelte';
|
||||
import { themeState } from '$lib/states/theme.svelte';
|
||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
|
||||
let mapContainer: HTMLDivElement | undefined = $state();
|
||||
let mapInstance: any = $state();
|
||||
|
||||
// Watch and react to mapState updates using a Svelte 5 $effect
|
||||
$effect(() => {
|
||||
const target = mapState.targetFlyTo;
|
||||
if (mapInstance && target) {
|
||||
untrack(() => {
|
||||
mapInstance.flyTo({
|
||||
center: [target.lng, target.lat],
|
||||
zoom: target.zoom,
|
||||
essential: true,
|
||||
duration: 1500
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (mapInstance) {
|
||||
const style = themeState.isLight
|
||||
? 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json'
|
||||
: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json';
|
||||
untrack(() => { mapInstance.setStyle(style); });
|
||||
}
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
if (!browser || !mapContainer) return;
|
||||
|
||||
const { Map, NavigationControl } = await import('maplibre-gl');
|
||||
|
||||
const map = new Map({
|
||||
container: mapContainer,
|
||||
style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
|
||||
center: [-76.9425, 38.9859], // UMD McKeldin Mall
|
||||
zoom: 15.5,
|
||||
pitch: 0,
|
||||
bearing: 0,
|
||||
attributionControl: false
|
||||
});
|
||||
|
||||
map.addControl(new NavigationControl({
|
||||
visualizePitch: true
|
||||
}), 'bottom-right');
|
||||
|
||||
mapInstance = map;
|
||||
|
||||
map.on('load', () => {
|
||||
map.addSource('study-locations', {
|
||||
type: 'geojson',
|
||||
data: {
|
||||
type: 'FeatureCollection',
|
||||
features: UMD_LOCATIONS.map(loc => ({
|
||||
type: 'Feature',
|
||||
geometry: { type: 'Point', coordinates: [loc.lng, loc.lat] },
|
||||
properties: { name: loc.name }
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: 'study-locations-labels',
|
||||
type: 'symbol',
|
||||
source: 'study-locations',
|
||||
layout: {
|
||||
'text-field': ['get', 'name'],
|
||||
'text-size': 13,
|
||||
'text-variable-anchor': ['top', 'bottom', 'left', 'right'],
|
||||
'text-radial-offset': 1,
|
||||
'text-justify': 'center'
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#ffffff',
|
||||
'text-halo-color': '#000000',
|
||||
'text-halo-width': 2
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
map.remove();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="absolute inset-0 z-0 bg-crust transition-colors duration-500">
|
||||
<div bind:this={mapContainer} class="absolute inset-0 z-0 {themeState.isLight ? 'mix-blend-normal opacity-100 filter brightness-105 contrast-125 grayscale' : 'mix-blend-luminosity opacity-90'} transition-all duration-500" style="width: 100%; height: 100%;"></div>
|
||||
<!-- Color Screen Wash -->
|
||||
<div class="absolute inset-0 pointer-events-none {themeState.isLight ? 'mix-blend-screen bg-white opacity-20' : 'mix-blend-color bg-crust opacity-100'} z-10 transition-all duration-500"></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(.maplibregl-ctrl-group) {
|
||||
background: rgba(15, 23, 42, 0.8) !important;
|
||||
backdrop-filter: blur(12px) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
border-left: 2px solid var(--color-neon-primary) !important;
|
||||
box-shadow: var(--shadow-glow-primary) !important;
|
||||
border-radius: 12px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
:global(.maplibregl-ctrl-group button) {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
|
||||
}
|
||||
:global(.maplibregl-ctrl-group button:last-child) {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
:global(.maplibregl-ctrl-icon) {
|
||||
filter: invert(1) opacity(0.8) !important;
|
||||
}
|
||||
:global(.maplibregl-ctrl-group button:hover) {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { mapState, UMD_LOCATIONS } from '$lib/states/map.svelte';
|
||||
|
||||
let { showDropdown = false } = $props<{ showDropdown?: boolean }>();
|
||||
|
||||
const legendItems = [
|
||||
{ label: 'Harmful (80+ dB)', color: '#f38ba8' },
|
||||
{ label: 'Disruptive (65-79 dB)', color: '#fab387' },
|
||||
{ label: 'Manageable (55-64 dB)', color: '#f9e2af' },
|
||||
{ label: 'Great (40-54 dB)', color: '#94e2d5' },
|
||||
{ label: 'Ideal (0-39 dB)', color: '#89b4fa' }
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="absolute top-6 right-6 md:right-8 z-20 flex flex-col gap-3 items-end">
|
||||
<div class="glass-panel p-4 md:p-5 rounded-2xl border-l-2 border-l-neon-primary flex flex-col gap-3" style="box-shadow: var(--shadow-glow-primary)">
|
||||
<h3 class="font-display font-medium text-white text-xs md:text-sm tracking-wider uppercase mb-1 border-b border-white/5 pb-2">Noise Levels</h3>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
{#each legendItems as item}
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-3.5 h-3.5 rounded shadow-sm shrink-0 border border-white/20" style="background-color: {item.color}; box-shadow: 0 0 8px {item.color}60"></div>
|
||||
<span class="text-xs font-mono text-slate-300 font-medium whitespace-nowrap">{item.label}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showDropdown}
|
||||
<div class="glass-panel rounded-xl border-l-2 border-l-neon-primary overflow-hidden flex flex-col w-64" style="box-shadow: var(--shadow-glow-primary)">
|
||||
<select class="bg-transparent text-white font-display text-sm p-4 border-none outline-none focus:ring-0 cursor-pointer w-full font-medium" onchange={(e) => {
|
||||
const val = (e.target as HTMLSelectElement).value;
|
||||
if (val === 'default') {
|
||||
mapState.flyHome();
|
||||
} else if (val) {
|
||||
const loc = UMD_LOCATIONS.find(l => l.name === val);
|
||||
if (loc) {
|
||||
mapState.flyTo(loc.lng, loc.lat, 18);
|
||||
}
|
||||
}
|
||||
}}>
|
||||
<option value="default" class="bg-crust text-white font-semibold text-center hidden md:block">Jump to Campus Area</option>
|
||||
{#each UMD_LOCATIONS as loc}
|
||||
<option value={loc.name} class="bg-crust text-white">{loc.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
export interface StudyLocation {
|
||||
id: string;
|
||||
name: string;
|
||||
hasFloors: boolean;
|
||||
floors?: string[];
|
||||
lng: number;
|
||||
lat: number;
|
||||
}
|
||||
|
||||
export const UMD_LOCATIONS: StudyLocation[] = [
|
||||
{ id: 'esj', name: 'Edward St. John (ESJ)', hasFloors: true, floors: ['Floor 1', 'Floor 2', 'Floor 3'], lng: -76.94209511596014, lat: 38.987133359608755 },
|
||||
{ id: 'mckeldin', name: 'McKeldin Library', hasFloors: true, floors: ['Floor 1', 'Floor 2', 'Floor 3', 'Floor 4', 'Floor 5', 'Floor 6', 'Floor 7'], lng: -76.94494907523277, lat: 38.986021017749366 },
|
||||
{ id: 'hornbake', name: 'Hornbake Library', hasFloors: false, lng: -76.94161787005467, lat: 38.988233373664826 },
|
||||
{ id: 'stem', name: 'STEM Library', hasFloors: false, lng: -76.93942003731279, lat: 38.988991437126195 },
|
||||
{ id: 'clarice', name: 'Clarice Library', hasFloors: false, lng: -76.94967344225785, lat: 38.99029330703877 },
|
||||
{ id: 'yahentamitsi', name: 'Yahentamitsi', hasFloors: false, lng: -76.9448027183373, lat: 38.99108961575231 },
|
||||
{ id: 'iribe', name: 'Iribe', hasFloors: false, lng: -76.93643838603555, lat: 38.98933701397555 },
|
||||
{ id: 'reckord', name: 'Reckord Armory', hasFloors: false, lng: -76.93897470250619, lat: 38.98609556181066 }
|
||||
];
|
||||
|
||||
export const DEFAULT_VIEW = { lng: -76.9425, lat: 38.9859, zoom: 15.5 };
|
||||
|
||||
class MapState {
|
||||
// The target coordinates the map should fly to
|
||||
targetFlyTo = $state<{ lng: number; lat: number; zoom: number; timestamp: number } | null>(null);
|
||||
|
||||
flyTo(lng: number, lat: number, zoom: number = 18) {
|
||||
this.targetFlyTo = { lng, lat, zoom, timestamp: Date.now() }; // timestamp ensures reactivity even if same coords
|
||||
}
|
||||
|
||||
flyHome() {
|
||||
this.flyTo(DEFAULT_VIEW.lng, DEFAULT_VIEW.lat, DEFAULT_VIEW.zoom);
|
||||
}
|
||||
}
|
||||
|
||||
export const mapState = new MapState();
|
||||
@@ -0,0 +1,18 @@
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
class ThemeState {
|
||||
isLight = $state(false);
|
||||
|
||||
toggle() {
|
||||
this.isLight = !this.isLight;
|
||||
if (browser) {
|
||||
if (this.isLight) {
|
||||
document.documentElement.classList.add('light-theme');
|
||||
} else {
|
||||
document.documentElement.classList.remove('light-theme');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const themeState = new ThemeState();
|
||||
@@ -1,9 +1,46 @@
|
||||
<script lang="ts">
|
||||
import './layout.css';
|
||||
import favicon from '$lib/assets/favicon.svg';
|
||||
// Make sure you have $app/environment or similar if you need active states,
|
||||
// for now we use simple routing links using sveltekit's native anchor tags.
|
||||
import Icon from '@iconify/svelte';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<svelte:head><link rel="icon" href={favicon} /></svelte:head>
|
||||
|
||||
<div class="h-screen w-full overflow-hidden bg-black text-slate-200 flex flex-col md:flex-row relative">
|
||||
|
||||
<!-- Floating Sidebar (Desktop) / Bottom Bar (Mobile) -->
|
||||
<nav class="absolute md:static bottom-4 left-1/2 md:left-4 -translate-x-1/2 md:translate-x-0 md:my-auto z-50 rounded-3xl glass-panel md:w-16 w-11/12 md:h-auto py-3 md:py-6 px-4 md:px-0 flex md:flex-col items-center justify-around md:justify-center gap-6 shadow-2xl border-white/10 md:mr-4 overflow-hidden relative">
|
||||
<!-- Shell Pattern Background -->
|
||||
<div class="absolute inset-0 pointer-events-none opacity-[0.08] z-0" style="background-image: url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2228%22 height=%2249%22 viewBox=%220 0 28 49%22%3E%3Cg fill-rule=%22evenodd%22%3E%3Cg id=%22hexagons%22 fill=%22%23ffffff%22 fill-opacity=%221%22 fill-rule=%22nonzero%22%3E%3Cpath d=%22M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z%22/%3E%3C/g%3E%3C/g%3E%3C/svg%3E'); background-repeat: repeat;"></div>
|
||||
|
||||
<!-- Nav Item: Live Map -->
|
||||
<a href="/" class="relative flex items-center justify-center p-3 rounded-2xl transition-all duration-300 hover:bg-white/10 group {$page.url.pathname === '/' ? 'text-neon-blue drop-shadow-[0_0_10px_rgba(0,243,255,0.6)] bg-white/5' : 'text-slate-400 hover:text-white'}">
|
||||
<Icon icon="mdi:map" class="text-2xl" />
|
||||
<span class="absolute left-full ml-4 px-2 py-1 bg-black/80 rounded text-xs opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none md:block hidden border border-white/10">Live Map</span>
|
||||
</a>
|
||||
|
||||
<!-- Nav Item: History Map -->
|
||||
<a href="/history" class="relative flex items-center justify-center p-3 rounded-2xl transition-all duration-300 hover:bg-white/10 group {$page.url.pathname === '/history' ? 'text-neon-blue drop-shadow-[0_0_10px_rgba(0,243,255,0.6)]' : 'text-slate-400 hover:text-white'}">
|
||||
<Icon icon="mdi:history" class="text-2xl" />
|
||||
<span class="absolute left-full ml-4 px-2 py-1 bg-black/80 rounded text-xs opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none md:block hidden border border-white/10">History</span>
|
||||
</a>
|
||||
|
||||
<div class="w-px h-6 md:w-6 md:h-px bg-white/10 my-2"></div>
|
||||
|
||||
<!-- Nav Item: Settings -->
|
||||
<a href="/settings" class="relative flex items-center justify-center p-3 rounded-2xl transition-all duration-300 hover:bg-white/10 group {$page.url.pathname === '/settings' ? 'text-neon-blue drop-shadow-[0_0_10px_rgba(0,243,255,0.6)]' : 'text-slate-400 hover:text-white'}">
|
||||
<Icon icon="mdi:cog-outline" class="text-2xl" />
|
||||
<span class="absolute left-full ml-4 px-2 py-1 bg-black/80 rounded text-xs opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none md:block hidden border border-white/10">Settings</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<main class="flex-1 relative w-full h-full overflow-hidden">
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,2 +1,26 @@
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import AlertsDropdown from '$lib/components/AlertsDropdown.svelte';
|
||||
import MapControls from '$lib/components/MapControls.svelte';
|
||||
import InteractiveMap from '$lib/components/InteractiveMap.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>EchoNode | Live Map</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="relative w-full h-full bg-crust border-l border-white/5">
|
||||
<InteractiveMap />
|
||||
|
||||
<MapControls showDropdown={true} />
|
||||
|
||||
<div class="absolute top-6 left-6 md:left-8 z-10 flex gap-4 items-center">
|
||||
<div class="glass-panel flex items-center gap-4 px-6 py-3 rounded-2xl shadow-lg border-l-2 border-l-neon-primary h-12" style="box-shadow: var(--shadow-glow-primary)">
|
||||
<h1 class="font-display font-semibold text-white tracking-wider flex items-center gap-2">
|
||||
<Icon icon="mdi:access-point-network" class="text-neon-primary text-lg" style="filter: drop-shadow(var(--shadow-glow-primary))" />
|
||||
LIVE DATA
|
||||
</h1>
|
||||
</div>
|
||||
<AlertsDropdown />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import MapControls from '$lib/components/MapControls.svelte';
|
||||
import InteractiveMap from '$lib/components/InteractiveMap.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>EchoNode | History</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="relative w-full h-full bg-crust border-l border-white/5">
|
||||
<!-- Map Engine Engine -->
|
||||
<InteractiveMap />
|
||||
|
||||
<MapControls showDropdown={true} />
|
||||
|
||||
<!-- Top Bar / History Mode Overlay -->
|
||||
<header class="absolute top-6 left-6 md:left-8 z-10">
|
||||
<div class="glass-panel flex items-center justify-between md:justify-start gap-4 px-6 py-3 rounded-2xl shadow-lg border-l-2 border-l-neon-blue drop-shadow-[0_0_10px_rgba(0,243,255,0.2)] h-12">
|
||||
<div>
|
||||
<h1 class="font-display font-semibold text-white tracking-wider flex items-center gap-2">
|
||||
<Icon icon="mdi:history" class="text-neon-blue drop-shadow-[0_0_5px_rgba(0,243,255,0.8)] text-lg" />
|
||||
HISTORICAL DATA
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Time Control Bottom Bar -->
|
||||
<div class="absolute bottom-24 md:bottom-8 left-4 md:left-8 right-4 md:right-8 z-10 flex justify-center">
|
||||
<div class="glass-panel rounded-2xl p-6 border-l-2 border-l-neon-primary w-full max-w-4xl" style="box-shadow: var(--shadow-glow-primary)">
|
||||
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h2 class="font-display font-medium text-lg text-white">Playback Controls</h2>
|
||||
<span class="text-neon-blue font-mono text-sm tracking-wider drop-shadow-[0_0_5px_rgba(0,243,255,0.5)]">Tue, Oct 14 - 14:00</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-6 mt-6">
|
||||
<button class="w-12 h-12 rounded-full bg-neon-blue/10 hover:bg-neon-blue/20 flex items-center justify-center text-neon-blue transition-colors border border-neon-blue/30 shrink-0">
|
||||
<Icon icon="mdi:play" class="text-2xl" />
|
||||
</button>
|
||||
|
||||
<!-- Slider Track -->
|
||||
<div class="flex-1 relative group cursor-pointer h-8 flex items-center">
|
||||
<div class="w-full h-1.5 bg-slate-800 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-neon-blue w-[60%] shadow-[0_0_10px_rgba(0,243,255,0.8)]"></div>
|
||||
</div>
|
||||
<!-- Slider Thumb -->
|
||||
<div class="absolute top-1/2 left-[60%] -translate-x-1/2 -translate-y-1/2 w-4 h-4 bg-white rounded-full shadow-[0_0_10px_rgba(255,255,255,0.8)] border-2 border-neon-blue group-hover:scale-125 transition-transform"></div>
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-slate-400 font-mono shrink-0">
|
||||
<p>24H Window</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,3 +1,59 @@
|
||||
@import 'tailwindcss';
|
||||
@plugin '@tailwindcss/forms';
|
||||
@plugin '@tailwindcss/typography';
|
||||
@theme {
|
||||
--font-sans: 'Comic Relief', 'Comic Neue', 'Comic Sans MS', cursive, system-ui, sans-serif;
|
||||
--font-display: 'Comic Relief', 'Comic Neue', 'Comic Sans MS', cursive, system-ui, sans-serif;
|
||||
|
||||
/* Catppuccin Theme */
|
||||
--color-crust: #11111b;
|
||||
--color-mantle: #181825;
|
||||
--color-base: #1e1e2e;
|
||||
--color-surface0: #313244;
|
||||
--color-surface1: #45475a;
|
||||
--color-surface2: #585b70;
|
||||
--color-red: #f38ba8;
|
||||
|
||||
--color-neon-primary: #f38ba8;
|
||||
--color-neon-alert: #f38ba8;
|
||||
--color-neon-blue: #f38ba8;
|
||||
--color-panel-glass: rgba(24, 24, 37, 0.7); /* Mantle Glass */
|
||||
|
||||
/* Glowing effects around elements */
|
||||
--shadow-glow-primary: 0 0 15px rgba(243, 139, 168, 0.4);
|
||||
--shadow-glow-alert: 0 0 15px rgba(243, 139, 168, 0.4);
|
||||
--shadow-glow-blue: 0 0 15px rgba(243, 139, 168, 0.4);
|
||||
}
|
||||
|
||||
.light-theme {
|
||||
--color-crust: #ffffff; /* Pure white background */
|
||||
--color-mantle: #cdd6f4;
|
||||
--color-base: #bac2de;
|
||||
--color-surface0: #9399b2; /* Darker buttons */
|
||||
--color-surface1: #7f849c;
|
||||
--color-surface2: #6c7086;
|
||||
--color-red: #e07290;
|
||||
--color-neon-primary: #e07290; /* Darker Pink */
|
||||
--color-neon-alert: #f38ba8;
|
||||
--color-neon-blue: #e07290; /* Darker Pink Accent */
|
||||
--color-panel-glass: rgba(255, 255, 255, 0.95); /* Bright White Glass for sidebar */
|
||||
color: #585b70 !important; /* Darkest Text */
|
||||
}
|
||||
|
||||
/* Override text colors globally for light mode */
|
||||
.light-theme .text-white, .light-theme .text-slate-200, .light-theme .text-slate-300, .light-theme .text-slate-400, .light-theme .text-slate-500 {
|
||||
color: #585b70 !important;
|
||||
}
|
||||
|
||||
.light-theme border-white {
|
||||
border-color: rgba(88, 91, 112, 0.1);
|
||||
}
|
||||
|
||||
@utility glass-panel {
|
||||
background-color: var(--color-panel-glass);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
@utility text-glow {
|
||||
text-shadow: 0 0 10px currentColor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import { themeState } from '$lib/states/theme.svelte';
|
||||
|
||||
function handleLightModeClick() {
|
||||
themeState.toggle();
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>EchoNode | Settings</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="relative w-full h-full bg-crust border-l border-white/5 p-6 md:p-12 overflow-y-auto duration-500 transition-colors">
|
||||
<!-- Background Mesh -->
|
||||
<div class="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-surface0/30 via-crust to-crust z-0 pointer-events-none transition-colors duration-500"></div>
|
||||
|
||||
<div class="relative z-10 max-w-4xl mx-auto">
|
||||
<header class="mb-10">
|
||||
<h1 class="font-display font-semibold text-3xl text-white tracking-wider flex items-center gap-3">
|
||||
<Icon icon="mdi:cog" class="text-slate-300" />
|
||||
SYSTEM SETTINGS
|
||||
</h1>
|
||||
<p class="text-sm text-slate-400 mt-2">Configure your interface preferences.</p>
|
||||
</header>
|
||||
|
||||
<section class="glass-panel p-6 md:p-8 rounded-2xl border-white/10 shadow-xl">
|
||||
<h2 class="font-display text-xl text-white mb-6 flex items-center gap-2 border-b border-white/10 pb-3">
|
||||
<Icon icon="mdi:palette-outline" class="text-neon-blue" />
|
||||
Appearance
|
||||
</h2>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between p-4 md:p-6 bg-mantle/40 rounded-xl border border-white/5 hover:border-white/10 transition-colors gap-4">
|
||||
<div class="pr-4">
|
||||
<h3 class="font-display font-medium text-white text-lg">Light / Dark Mode</h3>
|
||||
</div>
|
||||
|
||||
<button onclick={handleLightModeClick} class="shrink-0 px-5 py-2.5 bg-surface0 rounded-xl border border-white/10 hover:border-yellow-400/50 hover:text-yellow-400 hover:bg-surface1 transition-all flex items-center justify-center gap-2 font-medium">
|
||||
<Icon icon={themeState.isLight ? "mdi:weather-night" : "mdi:weather-sunny"} class="text-lg" />
|
||||
{themeState.isLight ? "Enable Dark Mode" : "Enable Light Mode"}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user