Repository: daison12006013/sveltekit-starter Branch: develop Commit: e761b9f39463 Files: 118 Total size: 357.1 KB Directory structure: gitextract_2mqan8mg/ ├── .env.example ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── guides/ │ └── laravel-sanctum.md ├── package.json ├── playwright.config.ts ├── postcss.config.cjs ├── run ├── src/ │ ├── app.css │ ├── app.d.ts │ ├── app.html │ ├── hooks/ │ │ ├── laravel-sanctum-fake-logged-in.ts │ │ ├── laravel-sanctum-fake-logged-out.ts │ │ ├── laravel-sanctum.ts │ │ └── sveltekit-default.ts │ ├── lib/ │ │ ├── Counter.svelte │ │ ├── components/ │ │ │ ├── Accordion.svelte │ │ │ ├── AccordionItem.svelte │ │ │ ├── Alert.svelte │ │ │ ├── Badge.svelte │ │ │ ├── Breadcrumb.svelte │ │ │ ├── ButtonGroup.svelte │ │ │ ├── Buttons.svelte │ │ │ ├── Card.svelte │ │ │ ├── Carousel.svelte │ │ │ ├── CloseButton.svelte │ │ │ ├── Code.svelte │ │ │ ├── Collapse.svelte │ │ │ ├── Docs/ │ │ │ │ ├── DocAccordion.svelte │ │ │ │ ├── DocAlert.svelte │ │ │ │ └── DocBadge.svelte │ │ │ ├── Dropdowns.svelte │ │ │ ├── ListGroup.svelte │ │ │ ├── Modal.svelte │ │ │ ├── NavsAndTabs.svelte │ │ │ ├── Pagination.svelte │ │ │ ├── Popovers.svelte │ │ │ ├── Spinners.svelte │ │ │ ├── Toasts.svelte │ │ │ └── Tooltips.svelte │ │ ├── form.ts │ │ ├── header/ │ │ │ └── Header.svelte │ │ ├── ioevents/ │ │ │ ├── click.ts │ │ │ └── keydown.ts │ │ ├── tailwind.css │ │ ├── templates/ │ │ │ ├── Admin/ │ │ │ │ ├── API/ │ │ │ │ │ └── form.ts │ │ │ │ ├── Config/ │ │ │ │ │ └── charts.ts │ │ │ │ ├── Header.svelte │ │ │ │ ├── SideBar.svelte │ │ │ │ └── ToggleTheme.svelte │ │ │ └── Blog/ │ │ │ ├── Config/ │ │ │ │ ├── links.json │ │ │ │ └── particle.json │ │ │ ├── Header.svelte │ │ │ ├── Particles/ │ │ │ │ ├── Particles.svelte │ │ │ │ ├── global.d.ts │ │ │ │ ├── index.d.ts │ │ │ │ └── index.ts │ │ │ └── SideBar.svelte │ │ └── translator.ts │ ├── routes/ │ │ ├── admin/ │ │ │ ├── (authenticated)/ │ │ │ │ ├── +layout.svelte │ │ │ │ ├── +page.svelte │ │ │ │ ├── buttons/ │ │ │ │ │ └── +page.svelte │ │ │ │ ├── cards/ │ │ │ │ │ └── +page.svelte │ │ │ │ ├── charts/ │ │ │ │ │ └── +page.svelte │ │ │ │ ├── components/ │ │ │ │ │ └── +page.svelte │ │ │ │ ├── forms/ │ │ │ │ │ └── +page.svelte │ │ │ │ ├── modals/ │ │ │ │ │ └── +page.svelte │ │ │ │ └── tables/ │ │ │ │ └── +page.svelte │ │ │ ├── (guest)/ │ │ │ │ ├── +layout.svelte │ │ │ │ ├── auth/ │ │ │ │ │ ├── login/ │ │ │ │ │ │ ├── +page.server.ts │ │ │ │ │ │ └── +page.svelte │ │ │ │ │ └── logout/ │ │ │ │ │ └── +page.server.ts │ │ │ │ ├── forgot-password/ │ │ │ │ │ └── +page.svelte │ │ │ │ └── register/ │ │ │ │ └── +page.svelte │ │ │ ├── +error.svelte │ │ │ ├── +layout.server.ts │ │ │ └── html_head.svelte │ │ ├── api.ts │ │ ├── blog/ │ │ │ ├── +layout.svelte │ │ │ ├── +page.svelte │ │ │ └── resume/ │ │ │ └── +page.svelte │ │ └── demo/ │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ ├── +page.ts │ │ ├── Counter.svelte │ │ ├── Header.svelte │ │ ├── about/ │ │ │ ├── +page.svelte │ │ │ └── +page.ts │ │ ├── styles.css │ │ └── sverdle/ │ │ ├── +page.server.ts │ │ ├── +page.svelte │ │ ├── game.test.ts │ │ ├── game.ts │ │ ├── how-to-play/ │ │ │ ├── +page.svelte │ │ │ └── +page.ts │ │ ├── reduced-motion.ts │ │ └── words.server.ts │ ├── service-worker.ts │ └── stores/ │ └── menus.ts ├── start/ │ ├── route.js │ ├── tailwind/ │ │ ├── admin.cjs │ │ ├── daisy-ui.cjs │ │ └── index.cjs │ └── vite/ │ ├── default.vite.config.js │ └── index.js ├── static/ │ ├── manifest.json │ └── robots.txt ├── svelte.config.js ├── tailwind.config.cjs ├── tests/ │ └── demo.ts ├── tsconfig.json └── vite.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .env.example ================================================ VITE_APP_NAME="Project Name" VITE_BASE_API="http://api.local" VITE_SESSION_NAME="laravel_session" # url path VITE_LOGIN_PATH="/auth/login" VITE_LOGOUT_PATH="/auth/logout" ================================================ FILE: .eslintignore ================================================ .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 ================================================ FILE: .eslintrc.cjs ================================================ module.exports = { root: true, parser: '@typescript-eslint/parser', extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], plugins: ['svelte3', '@typescript-eslint'], ignorePatterns: ['*.cjs'], overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], settings: { 'svelte3/typescript': () => require('typescript'), }, parserOptions: { sourceType: 'module', ecmaVersion: 2020, }, env: { browser: true, es2017: true, node: true, }, } ================================================ FILE: .gitignore ================================================ .vscode .DS_Store node_modules /build /.svelte-kit /package .env .env.* !.env.example .vercel .output /functions /.vercel_build_output /.idea /vite.config.js.timestamp* ================================================ FILE: .npmrc ================================================ engine-strict=true ================================================ FILE: .nvmrc ================================================ v16.14.2 ================================================ FILE: .prettierignore ================================================ .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 ================================================ FILE: .prettierrc ================================================ { "useTabs": true, "singleQuote": true, "trailingComma": "none", "printWidth": 100, "pluginSearchDirs": ["."], "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }], "semi": false } ================================================ FILE: README.md ================================================ # SvelteKit Projects - [./run and src/route.js](#run-and-srcroutejs) - [Playwright Test Cases](#playwright-test-cases) - [Demo](#demo) - [Framework Specific Guidelines](#framework-specific-guidelines) - [Disclaimer](#disclaimer) The copy of this branch should have at least the `v1.15.10` of `@sveltejs/kit` ## ./run and src/route.js Dynamic way of serving the `./src/routes/admin`, we've added a condition inside our `start/route.js` to pre-determine the folder we want. ```bash # this demonstrates a fake logged in $> ./run admin dev $> ./run admin-in dev # this demonstrates a fake logged out $> ./run admin-out dev # this connects to your laravel sanctum $> ./run admin-laravel-sanctum dev ``` The above command is similar to what it looks like below ```bash $> ROUTE_FOLDER=admin npm run dev ``` We've stored more route projects, such as the original `demo` of sveltekit and my own resumé `blog` ```bash # this demonstrates my bio and resumé $> ./run blog dev # this demonstrates the original sveltekit counter + todo $> ./run demo dev ``` ## Playwright Test Cases When writing a test cases, rule of thumb is to name your tests with/by specific words, such as **"demo:"** ```js // tests/demo.js test('demo: about page has expected h1', async ({ page }) => { // ... }); ``` Then you can run specific folders by executing it this way ```bash ./run demo test -- -g "demo:" ``` ## Demo - [Admin logged-in](https://sveltekit-windmill-admin.vercel.app/) - [Admin logged-out](https://sveltekit-windmill-admin-out.vercel.app/) - [Bio / Resumé](https://daison.vercel.app/) ## Framework Specific Guidelines - [Setup Laravel Sanctum](/guides/laravel-sanctum.md) - ***You have backend framework? Add your sveltekit guidelines here!*** ## Disclaimer - (Admin UI) Most of the design was based originally from [Estevan Maito's](https://github.com/estevanmaito/windmill-dashboard) ## Project Sponsors - https://formatterjson.com/ - https://jsonlinter.com/ ================================================ FILE: guides/laravel-sanctum.md ================================================ # SvelteKit + Laravel Sanctum Setup Install sanctum under your laravel ```bash laravel/ :~$ composer require laravel/sanctum ``` Add a new route group under your `app/Http/Kernel.php` ```php 'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ``` Under `routes/api.php` ```php Route::middleware('auth:sanctum')->group(['middleware' => 'auth:sanctum'], function () { Route::post('/login', function (Request $request) { $credentials = $request->validate([ 'email' => ['required', 'email'], 'password' => ['required'], ]); return response()->json(['authenticated' => Auth::attempt($credentials)]); }); Route::get('/logged-in', function (Request $request) { return response()->json([ 'user' => $request->user()->only('id', 'email', 'first_name', 'last_name', 'image'), ]); }); Route::match(['get', 'post'], '/logout', function (Request $request) { \Illuminate\Support\Facades\Auth::logout(); return response()->json(['authenticated' => false]); }); }); ``` The above code, we serve 3 routes, that is `/login`, `/logged-in` and `/logout` ## SvelteKit Starter Configuration Update the `hooks` inside **svelte.config.js** ```diff - hooks: `src/hooks/laravel-sanctum-fake-logged-in.ts`, + hooks: `src/hooks/laravel-sanctum.ts`, ``` Copy `.env.example` and make it `.env` ```bash sveltekit-starter/ :~$ cp .env.example .env ``` Then update the `VITE_BASE_API` based on your laravel url. ### How the hooks work? To explain about `laravel-sanctum.js` file - it will check if there are `locals.user` loaded, or else it fetches to your laravel endpoint `/logged-in` and passing the **user** object inside **locals.user** - then, if `laravel_session` does not exists, it will fetch `/sanctum/csrf-cookie` and sets the cookie ================================================ FILE: package.json ================================================ { "name": "sveltekit-starter", "version": "0.0.1", "scripts": { "dev": "vite dev", "build": "vite build", "preview": "vite preview", "test": "playwright test", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "test:unit": "vitest", "lint": "prettier --plugin-search-dir . --check . && eslint .", "format": "prettier --plugin-search-dir . --write ." }, "devDependencies": { "@fontsource/fira-mono": "^4.5.10", "@neoconfetti/svelte": "^1.0.0", "@playwright/test": "^1.28.1", "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/kit": "^1.5.0", "@types/cookie": "^0.5.1", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte": "^2.26.0", "prettier": "^2.8.0", "prettier-plugin-svelte": "^2.8.1", "svelte": "^3.54.0", "svelte-check": "^3.0.1", "tslib": "^2.4.1", "typescript": "^5.0.0", "vite": "^4.3.0", "vitest": "^0.25.3", "@sveltejs/adapter-vercel": "^1.0.0-next.62", "autoprefixer": "^10.2.5", "postcss": "^8.2.15", "svelte-bootstrap-icons": "^1.8.0", "tailwindcss": "^3.1.8", "tsparticles": "^2.2.4", "@esbuild-plugins/node-globals-polyfill": "^0.1.1", "@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@lukeed/uuid": "^2.0.0", "@tailwindcss/typography": "^0.5.7", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "cookie": "^0.4.1", "daisyui": "^2.27.0", "events": "^3.3.0", "leaflet": "^1.9.2", "process": "^0.11.10", "stream": "^0.0.2", "stream-browserify": "^3.0.0", "svelte-chartjs": "^1.0.1", "svelte-particles": "^2.2.4", "util": "^0.12.4" }, "type": "module" } ================================================ FILE: playwright.config.ts ================================================ import type { PlaywrightTestConfig } from '@playwright/test'; const config: PlaywrightTestConfig = { webServer: { command: 'npm run build && npm run preview', port: 4173 }, testDir: 'tests', testMatch: /(.+\.)?(test|spec)\.[jt]s/ }; export default config; ================================================ FILE: postcss.config.cjs ================================================ module.exports = { plugins: [require('tailwindcss'), require('autoprefixer')] } ================================================ FILE: run ================================================ #!/bin/bash # How to? # ./run {route-folder} {packages.scripts} # # As an example below: # ./run demo dev # ./run admin dev # ./run admin-in dev # ./run admin-out dev # ./run blog dev # ./run landing dev # # Others such as: # ./run admin build # ./run admin package ROUTE_FOLDER=$1 $(which npm) run $2 ${@:3} ================================================ FILE: src/app.css ================================================ @import '@fontsource/fira-mono'; :root { font-family: Arial, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; --font-mono: 'Fira Mono', monospace; --pure-white: #ffffff; --primary-color: #b9c6d2; --secondary-color: #d0dde9; --tertiary-color: #edf0f8; --accent-color: #ff3e00; --heading-color: rgba(0, 0, 0, 0.7); --text-color: #444444; --background-without-opacity: rgba(255, 255, 255, 0.7); --column-width: 42rem; --column-margin-top: 4rem; } body { min-height: 100vh; margin: 0; background-color: var(--primary-color); background: linear-gradient( 180deg, var(--primary-color) 0%, var(--secondary-color) 10.45%, var(--tertiary-color) 41.35% ); } body::before { content: ''; width: 80vw; height: 100vh; position: absolute; top: 0; left: 10vw; z-index: -1; background: radial-gradient( 50% 50% at 50% 50%, var(--pure-white) 0%, rgba(255, 255, 255, 0) 100% ); opacity: 0.05; } #svelte { min-height: 100vh; display: flex; flex-direction: column; } h1, h2, p { font-weight: 400; color: var(--heading-color); } p { line-height: 1.5; } a { color: var(--accent-color); text-decoration: none; } a:hover { text-decoration: underline; } h1 { font-size: 2rem; text-align: center; } h2 { font-size: 1rem; } pre { font-size: 16px; font-family: var(--font-mono); background-color: rgba(255, 255, 255, 0.45); border-radius: 3px; box-shadow: 2px 2px 6px rgb(255 255 255 / 25%); padding: 0.5em; overflow-x: auto; color: var(--text-color); } input, button { font-size: inherit; font-family: inherit; } button:focus:not(:focus-visible) { outline: none; } @media (min-width: 720px) { h1 { font-size: 2.4rem; } } ================================================ FILE: src/app.d.ts ================================================ // See https://kit.svelte.dev/docs#typescript // for information about these interfaces declare global { namespace App { // interface Error {} interface Locals { // sveltekit default userid: string; // laravel sanctum user: any; session: string; } interface Session { // laravel sanctum user: any; } // interface PageData {} // interface Platform {} } } export { }; ================================================ FILE: src/app.html ================================================ %sveltekit.head%
%sveltekit.body%
================================================ FILE: src/hooks/laravel-sanctum-fake-logged-in.ts ================================================ import cookie, { parse } from 'cookie'; import type { Handle } from '@sveltejs/kit'; // inside laravel-sanctum.ts // -> we're actually fetching the user who logged in // -> as well fetching a new session if the cookie is not present export const handle: Handle = async ({ event, resolve }) => { if (!event.locals.user) { event.locals.user = { id: 1, email: "janedoe@email.com", photo: "https://images.unsplash.com/photo-1502378735452-bc7d86632805?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=aa3a807e1bbdfd4364d1f449eaa96d82", first_name: "Jane", last_name: "Doe", } } const sessionName = import.meta.env.VITE_SESSION_NAME const cookies = cookie.parse(event.request.headers.get('cookie') || '') event.locals.session = cookies[sessionName] const response = await resolve(event) if (!event.locals.session) { // set cookie in the client response.headers.set( 'set-cookie', cookie.serialize(import.meta.env.VITE_SESSION_NAME, "this-is-a-fake-session") ) } return response }; ================================================ FILE: src/hooks/laravel-sanctum-fake-logged-out.ts ================================================ import type { Handle } from '@sveltejs/kit'; // since we want to simulate a FAKE log out // inside this hooks, we will do nothing! export const handle: Handle = async ({ event, resolve }) => { const response = await resolve(event) return response }; ================================================ FILE: src/hooks/laravel-sanctum.ts ================================================ import { api } from '$src/routes/api'; import cookie, { parse } from 'cookie'; import type { Handle } from '@sveltejs/kit'; export const handle: Handle = async ({ event, resolve }) => { if (!event.locals.user) { const loggedIn = await api({ method: 'get', resource: 'logged-in', event, }); event.locals.user = (await loggedIn.json()).user } const sessionName = import.meta.env.VITE_SESSION_NAME const cookies = cookie.parse(event.request.headers.get('cookie') || '') event.locals.session = cookies[sessionName] const response = await resolve(event) if (!event.locals.session) { const sanctum = await api({ method: 'get', resource: 'sanctum/csrf-cookie', event, }); if (sanctum.status === 204) { // set cookie in the client response.headers.set( 'set-cookie', sanctum.headers.get('set-cookie') ?? '' ) } } return response }; ================================================ FILE: src/hooks/sveltekit-default.ts ================================================ import type { Handle } from '@sveltejs/kit'; import * as cookie from 'cookie'; export const handle: Handle = async ({ event, resolve }) => { const cookies = cookie.parse(event.request.headers.get('cookie') || ''); event.locals.userid = cookies['userid'] || crypto.randomUUID(); const response = await resolve(event); if (!cookies['userid']) { // if this is the first time the user has visited this app, // set a cookie so that we recognise them when they return response.headers.set( 'set-cookie', cookie.serialize('userid', event.locals.userid, { path: '/', httpOnly: true }) ); } return response; }; ================================================ FILE: src/lib/Counter.svelte ================================================
{Math.floor($displayed_count)}
================================================ FILE: src/lib/components/Accordion.svelte ================================================
================================================ FILE: src/lib/components/AccordionItem.svelte ================================================
{#if show}
{/if}
================================================ FILE: src/lib/components/Alert.svelte ================================================
{#if body} {body} {:else} {/if}
================================================ FILE: src/lib/components/Badge.svelte ================================================ {#if body} {body} {:else} {/if} ================================================ FILE: src/lib/components/Breadcrumb.svelte ================================================ ================================================ FILE: src/lib/components/ButtonGroup.svelte ================================================ ================================================ FILE: src/lib/components/Buttons.svelte ================================================ ================================================ FILE: src/lib/components/Card.svelte ================================================ ================================================ FILE: src/lib/components/Carousel.svelte ================================================ ================================================ FILE: src/lib/components/CloseButton.svelte ================================================ ================================================ FILE: src/lib/components/Code.svelte ================================================ {#if language} // {language} {:else} {/if} {#if data.length} {#each data as datum, i}
{datum}
{#if data.length !== i + 1}
{/if} {/each} {:else} {/if}
================================================ FILE: src/lib/components/Collapse.svelte ================================================ ================================================ FILE: src/lib/components/Docs/DocAccordion.svelte ================================================ Accordion Eu laboris officia dolore non anim qui fugiat duis. Consectetur anim consequat commodo excepteur dolor commodo sint proident eu deserunt ea incididunt minim sint. Aliqua dolor tempor ex dolore magna tempor ullamco sunt sit sit veniam. Nisi proident cupidatat labore aliqua minim. Eiusmod ad laborum commodo elit anim cupidatat elit quis. My 2nd accordition with html element

Esse labore dolore reprehenderit est laboris labore. Deserunt pariatur nisi enim nulla elit minim laborum sunt sunt labore duis sit. Dolore incididunt minim eu est dolor velit adipisicing deserunt labore. Culpa aute nostrud magna aliqua exercitation reprehenderit sunt sit.

strong italic

Example:

{"import Accordion from '$lib/components/Accordion.svelte'"}
{"import AccordionItem from '$lib/components/AccordionItem.svelte'"}

{'// can be (primary, secondary, success, danger, warning, info, light, dark)'}
{"let type = 'danger'"}

{''}
  {'Text or HTML element here..
'}
  {'Text or HTML element here..'}
{''}
================================================ FILE: src/lib/components/Docs/DocAlert.svelte ================================================ Alerts A simple primary alert A simple secondary alert A simple success alert A simple danger alert A simple warning alert A simple info alert A simple light alert A simple dark alert

Example:

{"import Alert from '$lib/components/Alert.svelte'"}

{''}
{'A simple primary alert'}
================================================ FILE: src/lib/components/Docs/DocBadge.svelte ================================================ Badges
Hello World!

Example:

{"import Badge from '$lib/components/Badge.svelte'"}

{''}
{''}
{''}
{''}
{''}
{''}
{''}
{''}
{'Hello World!'}
================================================ FILE: src/lib/components/Dropdowns.svelte ================================================ ================================================ FILE: src/lib/components/ListGroup.svelte ================================================ ================================================ FILE: src/lib/components/Modal.svelte ================================================ ================================================ FILE: src/lib/components/NavsAndTabs.svelte ================================================ ================================================ FILE: src/lib/components/Pagination.svelte ================================================ ================================================ FILE: src/lib/components/Popovers.svelte ================================================ ================================================ FILE: src/lib/components/Spinners.svelte ================================================ ================================================ FILE: src/lib/components/Toasts.svelte ================================================ ================================================ FILE: src/lib/components/Tooltips.svelte ================================================ ================================================ FILE: src/lib/form.ts ================================================ import { invalidateAll } from '$app/navigation'; // this action (https://svelte.dev/tutorial/actions) allows us to // progressively enhance a
that already works without JS export function enhance( form: HTMLFormElement, { pending, error, result }: { pending?: ({ data, form }: { data: FormData; form: HTMLFormElement }) => void; error?: ({ data, form, response, error }: { data: FormData; form: HTMLFormElement; response: Response | null; error: Error | null; }) => void; result?: ({ data, form, response }: { data: FormData; response: Response; form: HTMLFormElement; }) => void; } = {} ) { let current_token: unknown; async function handle_submit(event: SubmitEvent) { const token = (current_token = {}); event.preventDefault(); const data = new FormData(form); if (pending) pending({ data, form }); try { const response = await fetch(form.action, { method: form.method, headers: { accept: 'application/json' }, body: data }); if (token !== current_token) return; if (response.ok) { if (result) result({ data, form, response }); invalidateAll(); } else if (error) { error({ data, form, error: null, response }); } else { console.error(await response.text()); } } catch (err: unknown) { if (error && err instanceof Error) { error({ data, form, error: err, response: null }); } else { throw err; } } } form.addEventListener('submit', handle_submit); return { destroy() { form.removeEventListener('submit', handle_submit); } }; } ================================================ FILE: src/lib/header/Header.svelte ================================================
================================================ FILE: src/lib/ioevents/click.ts ================================================ /** Dispatch event on click outside of node */ export function clickOutside(node: any, except: any[] = []) { const handle = (event: any) => { let shouldSkip = false except.forEach((val) => { if (document.getElementById(val)?.contains(event.target)) { shouldSkip = true } }) if (shouldSkip) { return } if (node && !node.contains(event.target) && !event.defaultPrevented) { node.dispatchEvent(new CustomEvent('click-outside', node)) } } document.addEventListener('click', handle, true) return { destroy() { document.removeEventListener('click', handle, true) }, } } ================================================ FILE: src/lib/ioevents/keydown.ts ================================================ /** Dispatch event on keydown Escape of node */ export function keydownEscape(node: any) { const handle = (event: any) => { if (event.key === 'Escape') { node.dispatchEvent(new CustomEvent('keydown-escape', node)) } } document.addEventListener('keydown', handle, true) return { destroy() { document.removeEventListener('keydown', handle, true) }, } } ================================================ FILE: src/lib/tailwind.css ================================================ @tailwind base; @tailwind components; @tailwind utilities; .bg-blog { @apply bg-blue-500; } .primary { @apply text-purple-100 bg-purple-600; } .secondary { @apply text-gray-100 bg-gray-500; } .success { @apply text-green-100 bg-green-600; } .danger { @apply text-red-100 bg-red-600; } .warning { @apply text-orange-100 bg-orange-600; } .info { @apply text-blue-100 bg-blue-600; } .light { @apply text-gray-700 bg-white; } .dark { @apply text-gray-100 bg-gray-700; } ================================================ FILE: src/lib/templates/Admin/API/form.ts ================================================ export default function enhance( form: HTMLFormElement, { pending, error, result, }: { pending?: (data: FormData, form: HTMLFormElement) => void error?: (res: Response, error: Error, form: HTMLFormElement) => void result: (res: Response, form: HTMLFormElement) => void } ) { async function handle(e: Event) { e.preventDefault() const body = new FormData(form) if (pending) pending(body, form) try { const res = await fetch(form.action, { method: form.method, headers: { accept: 'application/json', }, body, }) if (res.ok) { result(res, form) } else if (error) { error(res, null, form) } else { console.error(await res.text()) } } catch (e) { if (error) { error(null, e, form) } else { throw e } } } form.addEventListener('submit', handle) return { destroy() { form.removeEventListener('submit', handle) }, } } ================================================ FILE: src/lib/templates/Admin/Config/charts.ts ================================================ /** * For usage, visit Chart.js docs https://www.chartjs.org/docs/latest/ */ export const barConfig = { type: 'bar', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [ { label: 'Shoes', backgroundColor: '#0694a2', // borderColor: window.chartColors.red, borderWidth: 1, data: [-3, 14, 52, 74, 33, 90, 70], }, { label: 'Bags', backgroundColor: '#7e3af2', // borderColor: window.chartColors.blue, borderWidth: 1, data: [66, 33, 43, 12, 54, 62, 84], }, ], }, options: { responsive: true, legend: { display: false, }, }, } export const lineConfig = { type: 'line', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [ { label: 'Organic', /** * These colors come from Tailwind CSS palette * https://tailwindcss.com/docs/customizing-colors/#default-color-palette */ backgroundColor: '#0694a2', borderColor: '#0694a2', data: [43, 48, 40, 54, 67, 73, 70], fill: false, }, { label: 'Paid', fill: false, /** * These colors come from Tailwind CSS palette * https://tailwindcss.com/docs/customizing-colors/#default-color-palette */ backgroundColor: '#7e3af2', borderColor: '#7e3af2', data: [24, 50, 64, 74, 52, 51, 65], }, ], }, options: { responsive: true, /** * Default legends are ugly and impossible to style. * See examples in charts.html to add your own legends * */ legend: { display: false, }, tooltips: { mode: 'index', intersect: false, }, hover: { mode: 'nearest', intersect: true, }, scales: { x: { display: true, scaleLabel: { display: true, labelString: 'Month', }, }, y: { display: true, scaleLabel: { display: true, labelString: 'Value', }, }, }, }, } export const pieConfig = { type: 'doughnut', data: { datasets: [ { data: [33, 33, 33], /** * These colors come from Tailwind CSS palette * https://tailwindcss.com/docs/customizing-colors/#default-color-palette */ backgroundColor: ['#0694a2', '#1c64f2', '#7e3af2'], label: 'Dataset 1', }, ], labels: ['Shoes', 'Shirts', 'Bags'], }, options: { responsive: true, cutoutPercentage: 80, /** * Default legends are ugly and impossible to style. * See examples in charts.html to add your own legends * */ legend: { display: false, }, }, } ================================================ FILE: src/lib/templates/Admin/Header.svelte ================================================
{#if withSearch}
{/if}
================================================ FILE: src/lib/templates/Admin/SideBar.svelte ================================================
{#if withTitle} {appName} {/if}
================================================ FILE: src/lib/templates/Admin/ToggleTheme.svelte ================================================ ================================================ FILE: src/lib/templates/Blog/Config/links.json ================================================ [ { "name": "Home", "url": "/" }, { "name": "Resumé", "url": "/resume" } ] ================================================ FILE: src/lib/templates/Blog/Config/particle.json ================================================ { "particles": { "number": { "value": 24, "density": { "enable": true, "value_area": 800 } }, "color": { "value": "#ffffff" }, "shape": { "type": "circle", "stroke": { "width": 0, "color": "#000000" }, "polygon": { "nb_sides": 12 }, "image": { "src": "img/github.svg", "width": 100, "height": 100 } }, "opacity": { "value": 0.3, "random": false, "anim": { "enable": false, "speed": 1, "opacity_min": 0.1, "sync": false } }, "size": { "value": 3, "random": true, "anim": { "enable": false, "speed": 40, "size_min": 0.1, "sync": false } }, "line_linked": { "enable": true, "distance": 150, "color": "#ffffff", "opacity": 0.4, "width": 1 }, "move": { "enable": true, "speed": 0.5, "direction": "top-right", "random": true, "straight": false, "out_mode": "out", "bounce": false, "attract": { "enable": true, "rotateX": 600, "rotateY": 1200 } } }, "interactivity": { "detect_on": "canvas", "events": { "onhover": { "enable": false, "mode": "repulse" }, "onclick": { "enable": false, "mode": "push" }, "resize": true }, "modes": { "grab": { "distance": 400, "line_linked": { "opacity": 1 } }, "bubble": { "distance": 400, "size": 40, "duration": 2, "opacity": 5, "speed": 3 }, "repulse": { "distance": 200, "duration": 0.4 }, "push": { "particles_nb": 4 }, "remove": { "particles_nb": 2 } } }, "retina_detect": true } ================================================ FILE: src/lib/templates/Blog/Header.svelte ================================================
================================================ FILE: src/lib/templates/Blog/Particles/Particles.svelte ================================================
================================================ FILE: src/lib/templates/Blog/Particles/global.d.ts ================================================ /// ================================================ FILE: src/lib/templates/Blog/Particles/index.d.ts ================================================ import type { SvelteComponentTyped } from "svelte"; import type { ISourceOptions, Engine, Container } from "tsparticles-engine"; declare module "svelte-particles" { type CustomEventWrapper = { [K in keyof T]: CustomEvent; }; type ParticlesProps = { options?: ISourceOptions; url?: string; id?: string; particlesInit: (engine: Engine) => Promise; }; type ParticlesEvents = CustomEventWrapper<{ particlesLoaded: { particles?: Container; }; }>; export default class extends SvelteComponentTyped { } } ================================================ FILE: src/lib/templates/Blog/Particles/index.ts ================================================ export { default as default } from './Particles.svelte'; ================================================ FILE: src/lib/templates/Blog/SideBar.svelte ================================================
================================================ FILE: src/lib/translator.ts ================================================ const getLang = (): string => { // well, maybe base the language from // -> where the guest coming from? via API to determine their IP Address // -> or when they're logged in, base it from their // preferred language by storing that in the hooks // ohh, you should cache that too, :P return 'en' } const getData = (lang: string) => { // ofcourse get the data via api, below is just a sample! const data = { en: { Dashboard: 'Dashboard', 'Lorem :ipsum whatever': ':ipsum Lorem Sikador', 'Lorem {ipsum} whatever': '{ipsum} Lorem Sikador', }, } return data[lang] } export const trans = (text: string, replacers?: any, strict = false): string => { const lang = getLang() const data = getData(lang) let resp = data[text] if (resp === undefined) { if (strict) { throw Error(`Translation for ${text} not found under [${lang}] language.`) } resp = text } if (replacers !== undefined) { Object.keys(replacers).forEach((idx) => { resp = resp.replace(`:${idx}`, replacers[idx]) // Laravel like translations... resp = resp.replace(`{${idx}}`, replacers[idx]) // maybe uses curly braces? "My {text} whatever" }) } return resp } export default trans ================================================ FILE: src/routes/admin/(authenticated)/+layout.svelte ================================================
{#if $isSideMenuOpen}
{/if}
================================================ FILE: src/routes/admin/(authenticated)/+page.svelte ================================================ Dashboard

Dashboard

Star this project on GitHub
View more →

Total clients

6389

Account balance

$ 46,760.89

New sales

376

Pending contacts

35

Client Amount Status Date
$ 863.45 Approved 6/10/2020
$ 369.95 Pending 6/10/2020
$ 86.00 Denied 6/10/2020
$ 1276.45 Approved 6/10/2020
$ 863.45 Expired 6/10/2020
$ 863.45 Approved 6/10/2020
$ 863.45 Approved 6/10/2020
$ 863.45 Approved 6/10/2020
$ 863.45 Approved 6/10/2020
Showing 21-30 of 100

Charts

Revenue

Shirts
Shoes
Bags

Traffic

Organic
Paid
================================================ FILE: src/routes/admin/(authenticated)/buttons/+page.svelte ================================================ Buttons

Buttons

Star this project on GitHub
View more →

Sizes

Apply w-full to any button to create a block level button.

Icons

================================================ FILE: src/routes/admin/(authenticated)/cards/+page.svelte ================================================ Cards

Cards

Star this project on GitHub
View more →

Big section cards

Large, full width sections goes here

Responsive cards

Total clients

6389

Account balance

$ 46,760.89

New sales

376

Pending contacts

35

Cards with title

Revenue

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fuga, cum commodi a omnis numquam quod? Totam exercitationem quos hic ipsam at qui cum numquam, sed amet ratione! Ratione, nihil dolorum.

Colored card

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fuga, cum commodi a omnis numquam quod? Totam exercitationem quos hic ipsam at qui cum numquam, sed amet ratione! Ratione, nihil dolorum.

================================================ FILE: src/routes/admin/(authenticated)/charts/+page.svelte ================================================ {_i('Charts')}

Charts

{_i('Star this project on GitHub')}
{_i('View more')} →

{_i('Charts are provided by')} {_i('Chart.js')} . {_i( 'Note that the default legends are disabled and you should provide a description for your charts in HTML. See source code for examples.' )}

Doughnut/Pie

{_i('Shirts')}
{_i('Shoes')}
{_i('Bags')}

Lines

Organic
Paid

Bars

{_i('Shoes')}
{_i('Bags')}
================================================ FILE: src/routes/admin/(authenticated)/components/+page.svelte ================================================ Components



================================================ FILE: src/routes/admin/(authenticated)/forms/+page.svelte ================================================ Forms

Forms

Star this project on GitHub
View more →

Elements

Account Type