Adds a responsive menu
This commit is contained in:
7
package-lock.json
generated
7
package-lock.json
generated
@@ -21,6 +21,7 @@
|
|||||||
"@sveltejs/adapter-node": "^1.3.1",
|
"@sveltejs/adapter-node": "^1.3.1",
|
||||||
"@sveltejs/kit": "^1.20.4",
|
"@sveltejs/kit": "^1.20.4",
|
||||||
"@tailwindcss/forms": "^0.5.6",
|
"@tailwindcss/forms": "^0.5.6",
|
||||||
|
"@types/js-yaml": "^4.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
"@vitest/ui": "^0.34.1",
|
"@vitest/ui": "^0.34.1",
|
||||||
@@ -966,6 +967,12 @@
|
|||||||
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/js-yaml": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-ACTuifTSIIbyksx2HTon3aFtCKWcID7/h3XEmRpDYdMCXxPbl+m9GteOJeaAkiAta/NJaSFuA7ahZ0NkwajDSw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.12",
|
"version": "7.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"@sveltejs/adapter-node": "^1.3.1",
|
"@sveltejs/adapter-node": "^1.3.1",
|
||||||
"@sveltejs/kit": "^1.20.4",
|
"@sveltejs/kit": "^1.20.4",
|
||||||
"@tailwindcss/forms": "^0.5.6",
|
"@tailwindcss/forms": "^0.5.6",
|
||||||
|
"@types/js-yaml": "^4.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
"@vitest/ui": "^0.34.1",
|
"@vitest/ui": "^0.34.1",
|
||||||
|
|||||||
16
src/lib/components/Button.svelte
Normal file
16
src/lib/components/Button.svelte
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let buttonProps = {
|
||||||
|
class: [$$restProps.class]
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button
|
||||||
|
on:click
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
class="{$$restProps.class ||
|
||||||
|
''} flex h-8 w-8 items-center justify-center rounded-full p-0 transition-all hover:bg-neutral-600 active:bg-neutral-700 dark:active:bg-neutral-500"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</button>
|
||||||
72
src/lib/components/LinkMenu.svelte
Normal file
72
src/lib/components/LinkMenu.svelte
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Button from './Button.svelte';
|
||||||
|
|
||||||
|
let show = false;
|
||||||
|
export let links: Array<LinkConfig>;
|
||||||
|
|
||||||
|
function clickOutside(node) {
|
||||||
|
const handleClick = (event) => {
|
||||||
|
if (
|
||||||
|
node &&
|
||||||
|
!node.contains(event.target) &&
|
||||||
|
!event.defaultPrevented &&
|
||||||
|
node.offsetParent !== null
|
||||||
|
) {
|
||||||
|
node.dispatchEvent(new CustomEvent('click_outside', node));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', handleClick, true);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
document.removeEventListener('click', handleClick, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- small device menu button -->
|
||||||
|
<Button
|
||||||
|
class="md:hidden"
|
||||||
|
on:click={() => {
|
||||||
|
show = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i class="fa fa-bars" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- small device menu -->
|
||||||
|
<div
|
||||||
|
use:clickOutside
|
||||||
|
on:click_outside={() => {
|
||||||
|
show = false;
|
||||||
|
}}
|
||||||
|
class:hidden={!show}
|
||||||
|
class="min-w-40 absolute left-0 top-0 block flex flex-col gap-1 rounded border border-neutral-600 bg-neutral-600 p-1 transition-all"
|
||||||
|
>
|
||||||
|
{#each links as link}
|
||||||
|
<a
|
||||||
|
class="rounded p-2 transition-all hover:bg-neutral-500 active:bg-neutral-600 dark:hover:bg-neutral-700"
|
||||||
|
href={link.url}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{#if link.icon}
|
||||||
|
<i class={link.icon} />
|
||||||
|
{/if}
|
||||||
|
<span class="link-label">{link.title}</span>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- medium device menu -->
|
||||||
|
<div class="hidden flex-row justify-start gap-4 md:flex">
|
||||||
|
{#each links as link}
|
||||||
|
<a href={link.url} target="_blank">
|
||||||
|
{#if link.icon}
|
||||||
|
<i class={link.icon} />
|
||||||
|
{/if}
|
||||||
|
<span class="link-label">{link.title}</span>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
@@ -23,7 +23,7 @@ const requiredService: Required<ServiceConfig> = {
|
|||||||
target: '',
|
target: '',
|
||||||
type: '',
|
type: '',
|
||||||
tag: '',
|
tag: '',
|
||||||
keywords: []
|
keywords: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
const requiredServiceGroup: Required<ServiceGroupConfig> = {
|
const requiredServiceGroup: Required<ServiceGroupConfig> = {
|
||||||
@@ -96,7 +96,7 @@ const defaultDarkConfig: ColorConfig = {};
|
|||||||
|
|
||||||
export const defaultConfig: Config = {
|
export const defaultConfig: Config = {
|
||||||
title: 'Flanders',
|
title: 'Flanders',
|
||||||
columns: 3,
|
columns: 4,
|
||||||
colors: {
|
colors: {
|
||||||
light: defaultLightConfig,
|
light: defaultLightConfig,
|
||||||
dark: defaultDarkConfig
|
dark: defaultDarkConfig
|
||||||
@@ -112,7 +112,7 @@ function strip<Type extends SPOJO>(toStrip: Type, reference: Type): Type {
|
|||||||
if (reference == undefined) {
|
if (reference == undefined) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
const referenceNames = Object.entries(reference).map(([key, value]) => key);
|
const referenceNames = Object.entries(reference).map((v) => v[0]);
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(res)) {
|
for (const [key, value] of Object.entries(res)) {
|
||||||
if (referenceNames.includes(key) == false) {
|
if (referenceNames.includes(key) == false) {
|
||||||
@@ -171,7 +171,7 @@ export function watchDymamicConfig() {
|
|||||||
const reloadConfig = async () => {
|
const reloadConfig = async () => {
|
||||||
try {
|
try {
|
||||||
const dynamicConfig = yml.load(await readFile(__filepath, 'utf8'));
|
const dynamicConfig = yml.load(await readFile(__filepath, 'utf8'));
|
||||||
_serverConfig = mergeConfig(defaultConfig, dynamicConfig);
|
_serverConfig = mergeConfig(defaultConfig, dynamicConfig as SPOJO);
|
||||||
_clientConfig = stripPrivateFields(_serverConfig);
|
_clientConfig = stripPrivateFields(_serverConfig);
|
||||||
initializeServiceData();
|
initializeServiceData();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -184,6 +184,7 @@ export function watchDymamicConfig() {
|
|||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const watcher = watch(__filepath);
|
const watcher = watch(__filepath);
|
||||||
|
// eslint-disable-next-line
|
||||||
for await (const event of watcher) {
|
for await (const event of watcher) {
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import ViteYaml from '@modyfi/vite-plugin-yaml';
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
import ViteYaml from '@modyfi/vite-plugin-yaml';
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [ViteYaml(), sveltekit()],
|
plugins: [ViteYaml(), sveltekit()],
|
||||||
|
|||||||
Reference in New Issue
Block a user