mirror of
https://github.com/gurucomputing/headscale-ui.git
synced 2026-01-23 10:35:45 +00:00
initial rewrite of base UI
This commit is contained in:
parent
64b6c5dc75
commit
074cf4752e
76 changed files with 4873 additions and 1084 deletions
|
|
@ -1,13 +1,4 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
|
|
|
|||
13
.prettierrc
13
.prettierrc
|
|
@ -1,7 +1,16 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 400
|
||||
"printWidth": 1000,
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
1
archive/.npmrc
Normal file
1
archive/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
engine-strict=true
|
||||
13
archive/.prettierignore
Normal file
13
archive/.prettierignore
Normal file
|
|
@ -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
|
||||
7
archive/.prettierrc
Normal file
7
archive/.prettierrc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 400
|
||||
}
|
||||
3499
archive/package-lock.json
generated
Normal file
3499
archive/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
35
archive/package.json
Normal file
35
archive/package.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "headscale-ui",
|
||||
"version": "2024.10.10",
|
||||
"scripts": {
|
||||
"dev": "vite dev --port 8080 --host 0.0.0.0",
|
||||
"build": "vite build",
|
||||
"package": "vite package",
|
||||
"preview": "vite preview --https --port 443 --host 0.0.0.0",
|
||||
"stage": "/usr/bin/caddy run --adapter caddyfile --config ./Caddyfile",
|
||||
"check": "svelte-check --tsconfig ./jsconfig.json",
|
||||
"check:watch": "svelte-check --tsconfig ./jsconfig.json --watch",
|
||||
"lint": "prettier --check --plugin-search-dir=. .",
|
||||
"format": "prettier --write --plugin-search-dir=. ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3",
|
||||
"@sveltejs/adapter-static": "^3",
|
||||
"@sveltejs/kit": "^2",
|
||||
"@tailwindcss/typography": "^0",
|
||||
"@vitejs/plugin-basic-ssl": "^1",
|
||||
"autoprefixer": "^10",
|
||||
"daisyui": "^4",
|
||||
"fuse.js": "^7",
|
||||
"postcss": "^8",
|
||||
"postcss-load-config": "^5",
|
||||
"prettier": "^3",
|
||||
"prettier-plugin-svelte": "^3",
|
||||
"svelte": "^4",
|
||||
"svelte-check": "^3",
|
||||
"svelte-preprocess": "^5",
|
||||
"tailwindcss": "^3",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
24
archive/src/app.css
Normal file
24
archive/src/app.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* Write your global styles here, in PostCSS syntax */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.form-input {
|
||||
@apply shadow appearance-none border rounded w-full bg-base-100 py-2 px-3 text-base-content text-sm mb-3 leading-tight focus:outline-none;
|
||||
}
|
||||
|
||||
.card-primary {
|
||||
@apply grid grid-cols-1 divide-y p-2 max-w-screen-lg mx-4 border-base-content rounded-md text-sm text-base-content shadow
|
||||
}
|
||||
|
||||
.card-pending {
|
||||
@apply flex justify-between p-1 mb-4 max-w-screen-lg border border-dashed mx-4 border-base-content rounded-md text-sm text-base-content shadow
|
||||
}
|
||||
|
||||
.card-input {
|
||||
@apply shadow appearance-none border rounded w-64 py-1 px-3 bg-base-100 text-base-content text-sm leading-tight focus:outline-none;
|
||||
}
|
||||
|
||||
.card-select {
|
||||
@apply shadow border rounded w-64 py-1 px-3 bg-base-100 text-base-content text-sm leading-tight focus:outline-2;
|
||||
}
|
||||
10
archive/src/app.d.ts
vendored
Normal file
10
archive/src/app.d.ts
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare namespace App {
|
||||
// interface Locals {}
|
||||
// interface Platform {}
|
||||
// interface Session {}
|
||||
// interface Stuff {}
|
||||
}
|
||||
12
archive/src/app.html
Normal file
12
archive/src/app.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
30
archive/src/routes/+layout.svelte
Normal file
30
archive/src/routes/+layout.svelte
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import Nav from '$lib/common/nav.svelte';
|
||||
import Alert from '$lib/common/Alert.svelte';
|
||||
import Stores from '$lib/common/Stores.svelte';
|
||||
import { themeStore } from '$lib/common/stores.js'
|
||||
|
||||
|
||||
// NOTE: the element that is using one of the theme attributes must be in the DOM on mount
|
||||
</script>
|
||||
|
||||
<main data-theme={$themeStore} class="flex flex-col">
|
||||
<!-- initialize localStorage -->
|
||||
<Stores></Stores>
|
||||
<div class="flex">
|
||||
<!-- sidebar -->
|
||||
<Nav />
|
||||
<!-- main window -->
|
||||
<div class="flex flex-1 min-w-0 flex-col bg-base-100">
|
||||
<Alert />
|
||||
<!-- header -->
|
||||
<!-- <div class="flex bg-gray-100 h-12 p-4">Header</div> -->
|
||||
<!-- content -->
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="flex">Footer</div> -->
|
||||
</main>
|
||||
9
archive/src/routes/+page.svelte
Normal file
9
archive/src/routes/+page.svelte
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
onMount(async () => {
|
||||
goto(`${base}/users.html`);
|
||||
});
|
||||
</script>
|
||||
26
archive/svelte.config.js
Normal file
26
archive/svelte.config.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import adapter from '@sveltejs/adapter-static';
|
||||
import preprocess from 'svelte-preprocess';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
fallback: 'index.html',
|
||||
precompress: false
|
||||
}),
|
||||
paths: {
|
||||
base: "/web"
|
||||
},
|
||||
csp: {
|
||||
mode: "hash",
|
||||
directives: { "script-src": ["self"] },
|
||||
}
|
||||
},
|
||||
preprocess: [
|
||||
preprocess({
|
||||
postcss: true
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
export default config;
|
||||
1716
package-lock.json
generated
1716
package-lock.json
generated
File diff suppressed because it is too large
Load diff
58
package.json
58
package.json
|
|
@ -1,35 +1,33 @@
|
|||
{
|
||||
"name": "headscale-ui",
|
||||
"version": "2024.10.10",
|
||||
"name": "base-frontend",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev --port 8080 --host 0.0.0.0",
|
||||
"dev": "vite dev --host 0.0.0.0 --port 8080",
|
||||
"build": "vite build",
|
||||
"package": "vite package",
|
||||
"preview": "vite preview --https --port 443 --host 0.0.0.0",
|
||||
"stage": "/usr/bin/caddy run --adapter caddyfile --config ./Caddyfile",
|
||||
"check": "svelte-check --tsconfig ./jsconfig.json",
|
||||
"check:watch": "svelte-check --tsconfig ./jsconfig.json --watch",
|
||||
"lint": "prettier --check --plugin-search-dir=. .",
|
||||
"format": "prettier --write --plugin-search-dir=. ."
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3",
|
||||
"@sveltejs/adapter-static": "^3",
|
||||
"@sveltejs/kit": "^2",
|
||||
"@tailwindcss/typography": "^0",
|
||||
"@vitejs/plugin-basic-ssl": "^1",
|
||||
"autoprefixer": "^10",
|
||||
"daisyui": "^4",
|
||||
"fuse.js": "^7",
|
||||
"postcss": "^8",
|
||||
"postcss-load-config": "^5",
|
||||
"prettier": "^3",
|
||||
"prettier-plugin-svelte": "^3",
|
||||
"svelte": "^4",
|
||||
"svelte-check": "^3",
|
||||
"svelte-preprocess": "^5",
|
||||
"tailwindcss": "^3",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/adapter-static": "^3.0.6",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"daisyui": "^4.12.14",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier-plugin-svelte": "^3.2.6",
|
||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||
"svelecte": "^5.1.1",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"tailwindcss": "^3.4.9",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
||||
61
src/app.css
61
src/app.css
|
|
@ -1,24 +1,41 @@
|
|||
/* Write your global styles here, in PostCSS syntax */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
.form-input {
|
||||
@apply shadow appearance-none border rounded w-full bg-base-100 py-2 px-3 text-base-content text-sm mb-3 leading-tight focus:outline-none;
|
||||
}
|
||||
|
||||
.card-primary {
|
||||
@apply grid grid-cols-1 divide-y p-2 max-w-screen-lg mx-4 border-base-content rounded-md text-sm text-base-content shadow
|
||||
}
|
||||
|
||||
.card-pending {
|
||||
@apply flex justify-between p-1 mb-4 max-w-screen-lg border border-dashed mx-4 border-base-content rounded-md text-sm text-base-content shadow
|
||||
}
|
||||
|
||||
.card-input {
|
||||
@apply shadow appearance-none border rounded w-64 py-1 px-3 bg-base-100 text-base-content text-sm leading-tight focus:outline-none;
|
||||
}
|
||||
|
||||
.card-select {
|
||||
@apply shadow border rounded w-64 py-1 px-3 bg-base-100 text-base-content text-sm leading-tight focus:outline-2;
|
||||
/* css settings for svelecte dependency */
|
||||
@layer components {
|
||||
.svelecte {
|
||||
--sv-min-height: 40px;
|
||||
--sv-bg: oklch(var(--b1));
|
||||
--sv-disabled-bg: oklch(var(--nc));
|
||||
--sv-border: 1px solid #626262;
|
||||
--sv-border-radius: 4px;
|
||||
--sv-general-padding: 4px;
|
||||
--sv-control-bg: var(--sv-bg);
|
||||
--sv-item-wrap-padding: 3px 3px 3px 6px;
|
||||
--sv-item-selected-bg: #626262;
|
||||
--sv-item-btn-color: #ccc;
|
||||
--sv-item-btn-color-hover: #ccc;
|
||||
--sv-item-btn-bg: #626262;
|
||||
--sv-item-btn-bg-hover: #bc6063;
|
||||
--sv-icon-color: #bbb;
|
||||
--sv-icon-color-hover: #ccc;
|
||||
--sv-icon-bg: transparent;
|
||||
--sv-icon-size: 20px;
|
||||
--sv-separator-bg: #626262;
|
||||
--sv-btn-border: 0;
|
||||
--sv-placeholder-color: #ccccd6;
|
||||
--sv-dropdown-bg: var(--sv-bg);
|
||||
--sv-dropdown-border: var(--sv-border);
|
||||
--sv-dropdown-offset: 1px;
|
||||
--sv-dropdown-width: auto;
|
||||
--sv-dropdown-shadow: 0 1px 3px #555;
|
||||
--sv-dropdown-height: 320px;
|
||||
--sv-dropdown-active-bg: oklch(var(--b3));
|
||||
--sv-dropdown-selected-bg: #754545;
|
||||
--sv-create-kbd-border: 1px solid #626262;
|
||||
--sv-create-kbd-bg: #626262;
|
||||
--sv-create-disabled-bg: #fcbaba;
|
||||
--sv-loader-border: 2px solid #626262;
|
||||
}
|
||||
}
|
||||
19
src/app.d.ts
vendored
19
src/app.d.ts
vendored
|
|
@ -1,10 +1,13 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare namespace App {
|
||||
// interface Locals {}
|
||||
// interface Platform {}
|
||||
// interface Session {}
|
||||
// interface Stuff {}
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export { };
|
||||
|
|
|
|||
25
src/app.html
25
src/app.html
|
|
@ -1,12 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/site/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
29
src/lib/classes.svelte.ts
Normal file
29
src/lib/classes.svelte.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
export class PersistentAppSettingsObject {
|
||||
daisyUITheme = "" // for setting the UI theme. See https://daisyui.com/docs/themes/
|
||||
|
||||
public constructor(init?: Partial<PersistentAppSettingsObject>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
export class AppSettingsObject {
|
||||
navbarTitle = "" // for setting the title of the page
|
||||
appLoaded = false // for hiding the screen until hydration has completed
|
||||
sidebarDrawerOpen = false // for determining if the sidebar is open when on a small screen
|
||||
toastAlerts: toastAlert[] = [] // for adding or removing alerts
|
||||
|
||||
public constructor(init?: Partial<AppSettingsObject>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
// alert used for populating toasts in the layout
|
||||
export class toastAlert {
|
||||
message = "" //message to display
|
||||
notificationType = "alert" //to style the toast
|
||||
id = "" //UUID generated to reference the toast
|
||||
|
||||
public constructor(init?: Partial<toastAlert>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
17
src/lib/components/layout/navbar.svelte
Normal file
17
src/lib/components/layout/navbar.svelte
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!-- nav bar content here -->
|
||||
<script lang="ts">
|
||||
import { appSettings } from '$lib/state.svelte';
|
||||
</script>
|
||||
|
||||
<div class="flex-1">
|
||||
<button
|
||||
aria-label="open sidebar"
|
||||
onclick={() => {
|
||||
appSettings.sidebarDrawerOpen = true;
|
||||
}}
|
||||
class="btn-square btn-ghost mask drawer-button mask-squircle btn-sm lg:hidden"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="m-1 h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" /></svg>
|
||||
</button>
|
||||
<div class="p-1"><h1 class="bold text-xl text-primary">{appSettings.navbarTitle}</h1></div>
|
||||
</div>
|
||||
42
src/lib/components/layout/sidebar.svelte
Normal file
42
src/lib/components/layout/sidebar.svelte
Normal file
File diff suppressed because one or more lines are too long
41
src/lib/components/layout/toast.svelte
Normal file
41
src/lib/components/layout/toast.svelte
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<!-- used to generate alerts or messages -->
|
||||
<script lang="ts">
|
||||
import { appSettings } from '$lib/state.svelte';
|
||||
let { toastAlert } = $props();
|
||||
|
||||
let progress = $state(100);
|
||||
|
||||
// sets a timer and removes the alert after totalTime miliseconds
|
||||
const intervalTime = 20; // 20ms
|
||||
const totalTime = 4000; // 4 seconds
|
||||
const decrement = 100 / (totalTime / intervalTime);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
progress -= decrement;
|
||||
if (progress <= 0) {
|
||||
progress = 0;
|
||||
removeAlert();
|
||||
}
|
||||
}, intervalTime);
|
||||
|
||||
// Removes alert early on button press
|
||||
function removeAlert() {
|
||||
clearInterval(interval); // Stop the interval at 0
|
||||
appSettings.toastAlerts = appSettings.toastAlerts.filter(function (returnObj) {
|
||||
return returnObj.id !== toastAlert.id;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="alert flex justify-between min-w-60 text-wrap">
|
||||
<div>{toastAlert.message}</div>
|
||||
<div>
|
||||
<button aria-label="close notification" class="mask mask-circle hover:bg-base-300" onclick={() => removeAlert()}>
|
||||
<div class="radial-progress" style="--value:{progress}; --size:2rem; --thickness: 2px;" role="progressbar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
1
src/lib/index.ts
Normal file
1
src/lib/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
||||
16
src/lib/state.svelte
Normal file
16
src/lib/state.svelte
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<script module lang="ts">
|
||||
import { AppSettingsObject, PersistentAppSettingsObject } from './classes.svelte';
|
||||
|
||||
// defines global state objects for the application
|
||||
export let appSettings = $state({
|
||||
navbarTitle: '',
|
||||
appLoaded: false,
|
||||
sidebarDrawerOpen: false,
|
||||
toastAlerts: []
|
||||
} as AppSettingsObject);
|
||||
|
||||
// defines global state objects that get written to localStorage for persistence
|
||||
export let persistentAppSettings = $state({
|
||||
daisyUITheme: ''
|
||||
} as PersistentAppSettingsObject);
|
||||
</script>
|
||||
|
|
@ -1,30 +1,79 @@
|
|||
<script lang="ts">
|
||||
import { toastAlert, type PersistentAppSettingsObject } from '$lib/classes.svelte';
|
||||
import Toast from '$lib/components/layout/toast.svelte';
|
||||
import Navbar from '$lib/components/layout/navbar.svelte';
|
||||
import Sidebar from '$lib/components/layout/sidebar.svelte';
|
||||
import { appSettings, persistentAppSettings } from '$lib/state.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import '../app.css';
|
||||
import Nav from '$lib/common/nav.svelte';
|
||||
import Alert from '$lib/common/Alert.svelte';
|
||||
import Stores from '$lib/common/Stores.svelte';
|
||||
import { themeStore } from '$lib/common/stores.js'
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
// NOTE: the element that is using one of the theme attributes must be in the DOM on mount
|
||||
onMount(async () => {
|
||||
// monitor the persistent app store and read/write to local storage as required
|
||||
// load existing persistentAppSettings from localStorage
|
||||
let localStorageAppSettings = JSON.parse(localStorage.getItem('persistentAppSettings') || '{}') as PersistentAppSettingsObject;
|
||||
Object.assign(persistentAppSettings, localStorageAppSettings);
|
||||
|
||||
// track when persistentAppSettings changes and write it back into localStorage
|
||||
$effect(() => {
|
||||
localStorage.setItem('persistentAppSettings', JSON.stringify(persistentAppSettings));
|
||||
});
|
||||
|
||||
// delay load until page is hydrated
|
||||
appSettings.appLoaded = true;
|
||||
|
||||
// alert test
|
||||
// appSettings.toastAlerts.push(
|
||||
// new toastAlert({
|
||||
// message: 'this is a test message',
|
||||
// id: crypto.randomUUID()
|
||||
// })
|
||||
// );
|
||||
|
||||
// appSettings.toastAlerts.push(
|
||||
// new toastAlert({
|
||||
// message: 'this is a test message too and super long and long and long',
|
||||
// id: crypto.randomUUID()
|
||||
// })
|
||||
// );
|
||||
});
|
||||
</script>
|
||||
|
||||
<main data-theme={$themeStore} class="flex flex-col">
|
||||
<!-- initialize localStorage -->
|
||||
<Stores></Stores>
|
||||
<div class="flex">
|
||||
<!-- sidebar -->
|
||||
<Nav />
|
||||
<!-- main window -->
|
||||
<div class="flex flex-1 min-w-0 flex-col bg-base-100">
|
||||
<Alert />
|
||||
<!-- header -->
|
||||
<!-- <div class="flex bg-gray-100 h-12 p-4">Header</div> -->
|
||||
<!-- content -->
|
||||
<div>
|
||||
<slot />
|
||||
{#if appSettings.appLoaded}
|
||||
<!-- daisy UI theme and menu settings -->
|
||||
<main data-theme={persistentAppSettings.daisyUITheme} in:fade={{ duration: 200 }} class="drawer lg:drawer-open">
|
||||
<input id="drawer-toggle" type="checkbox" class="drawer-toggle" checked={appSettings.sidebarDrawerOpen ? true : null} />
|
||||
<div class="drawer-content flex flex-col">
|
||||
<!-- toast content -->
|
||||
<div class="toast toast-center toast-top z-40">
|
||||
{#each appSettings.toastAlerts as toast}
|
||||
<div transition:fade={{ duration: 200 }}>
|
||||
<Toast toastAlert={toast}></Toast>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<!-- Navbar Content -->
|
||||
<div class="navbar h-10 min-h-0 border-b-2 bg-base-100">
|
||||
<Navbar></Navbar>
|
||||
</div>
|
||||
<!-- Page Content -->
|
||||
<div class="ml-5 mr-5 mt-5 min-h-screen items-center justify-center">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="flex">Footer</div> -->
|
||||
</main>
|
||||
<!-- Sidebar Content -->
|
||||
<div class="drawer-side">
|
||||
<button
|
||||
aria-label="close sidebar"
|
||||
class="drawer-overlay lg:hidden"
|
||||
onclick={() => {
|
||||
appSettings.sidebarDrawerOpen = false;
|
||||
}}
|
||||
></button>
|
||||
<ul class="menu min-h-full w-44 border-e-2 bg-base-100 p-1">
|
||||
<Sidebar></Sidebar>
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
{/if}
|
||||
|
|
|
|||
1
src/routes/+layout.ts
Normal file
1
src/routes/+layout.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const prerender = true;
|
||||
|
|
@ -4,6 +4,6 @@
|
|||
import { onMount } from 'svelte';
|
||||
|
||||
onMount(async () => {
|
||||
goto(`${base}/users.html`);
|
||||
goto(`${base}/users`);
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
12
src/routes/settings/+page.svelte
Normal file
12
src/routes/settings/+page.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { appSettings, persistentAppSettings } from '$lib/state.svelte';
|
||||
import Svelecte from 'svelecte';
|
||||
|
||||
appSettings.navbarTitle = 'Settings';
|
||||
appSettings.sidebarDrawerOpen = false;
|
||||
</script>
|
||||
|
||||
<div class="max-w-96">
|
||||
<h1 class="mb-4 text-primary">Application Theme</h1>
|
||||
<Svelecte name="daisyUITheme" options={['hsui', 'light', 'dark', 'cupcake', 'bumblebee', 'emerald', 'corporate', 'synthwave', 'retro', 'cyberpunk', 'valentine', 'halloween', 'garden', 'forest', 'aqua', 'lofi', 'pastel', 'fantasy', 'wireframe', 'black', 'luxury', 'dracula', 'cmyk', 'autumn', 'business', 'acid', 'lemonade', 'night', 'coffee', 'winter', 'dim', 'nord', 'sunset']} bind:value={persistentAppSettings.daisyUITheme} />
|
||||
</div>
|
||||
8
src/routes/users/+page.svelte
Normal file
8
src/routes/users/+page.svelte
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { appSettings } from '$lib/state.svelte';
|
||||
|
||||
appSettings.navbarTitle = 'Users';
|
||||
appSettings.sidebarDrawerOpen = false;
|
||||
</script>
|
||||
|
||||
Users
|
||||
|
|
@ -1,26 +1,26 @@
|
|||
import adapter from '@sveltejs/adapter-static';
|
||||
import preprocess from 'svelte-preprocess';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://svelte.dev/docs/kit/integrations
|
||||
// for more information about preprocessors
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
fallback: 'index.html',
|
||||
precompress: false
|
||||
// default options are shown. On some platforms
|
||||
// these options are set automatically — see below
|
||||
pages: 'build',
|
||||
assets: 'build',
|
||||
fallback: undefined,
|
||||
precompress: false,
|
||||
strict: true
|
||||
}),
|
||||
paths: {
|
||||
base: "/web"
|
||||
},
|
||||
csp: {
|
||||
mode: "hash",
|
||||
directives: { "script-src": ["self"] },
|
||||
base: '/web'
|
||||
}
|
||||
},
|
||||
preprocess: [
|
||||
preprocess({
|
||||
postcss: true
|
||||
})
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
63
tailwind.config.ts
Normal file
63
tailwind.config.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import containerQueries from '@tailwindcss/container-queries';
|
||||
import typography from '@tailwindcss/typography';
|
||||
import type { Config } from 'tailwindcss';
|
||||
import daisyui from 'daisyui';
|
||||
|
||||
export default {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
|
||||
daisyui: {
|
||||
themes: [
|
||||
{
|
||||
hsui: {
|
||||
"primary": "#065f46",
|
||||
"secondary": "#0369a1",
|
||||
"accent": "#6b21a8",
|
||||
"neutral": "#78716c",
|
||||
"base-100": "#FFFFFF",
|
||||
"info": "#3ABFF8",
|
||||
"success": "#36D399",
|
||||
"warning": "#FBBD23",
|
||||
"error": "#F87272",
|
||||
},
|
||||
},
|
||||
"light",
|
||||
"dark",
|
||||
"cupcake",
|
||||
"bumblebee",
|
||||
"emerald",
|
||||
"corporate",
|
||||
"synthwave",
|
||||
"retro",
|
||||
"cyberpunk",
|
||||
"valentine",
|
||||
"halloween",
|
||||
"garden",
|
||||
"forest",
|
||||
"aqua",
|
||||
"lofi",
|
||||
"pastel",
|
||||
"fantasy",
|
||||
"wireframe",
|
||||
"black",
|
||||
"luxury",
|
||||
"dracula",
|
||||
"cmyk",
|
||||
"autumn",
|
||||
"business",
|
||||
"acid",
|
||||
"lemonade",
|
||||
"night",
|
||||
"coffee",
|
||||
"winter",
|
||||
"dim",
|
||||
"nord",
|
||||
"sunset"
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [typography, containerQueries, daisyui]
|
||||
} satisfies Config;
|
||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
6
vite.config.ts
Normal file
6
vite.config.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue