aboutsummaryrefslogtreecommitdiffstats
path: root/apps/kit
diff options
context:
space:
mode:
Diffstat (limited to 'apps/kit')
-rw-r--r--apps/kit/src/lib/components/alert.svelte96
-rw-r--r--apps/kit/src/lib/components/button.svelte19
-rw-r--r--apps/kit/src/lib/components/icons/bars-3-center-left.svelte15
-rw-r--r--apps/kit/src/lib/components/icons/calendar.svelte14
-rw-r--r--apps/kit/src/lib/components/icons/chevron-up-down.svelte13
-rw-r--r--apps/kit/src/lib/components/icons/folder-open.svelte14
-rw-r--r--apps/kit/src/lib/components/icons/index.ts42
-rw-r--r--apps/kit/src/lib/components/icons/magnifying-glass.svelte13
-rw-r--r--apps/kit/src/lib/components/icons/megaphone.svelte14
-rw-r--r--apps/kit/src/lib/components/icons/queue-list.svelte14
-rw-r--r--apps/kit/src/lib/components/input.svelte58
-rw-r--r--apps/kit/src/lib/components/locale-switcher.svelte45
-rw-r--r--apps/kit/src/routes/(main)/(app)/+layout.svelte534
-rw-r--r--apps/kit/src/routes/(main)/(app)/org/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/(app)/profile/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/(app)/projects/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/(app)/settings/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/(app)/tickets/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/(app)/todo/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/(app)/wiki/+page.svelte4
-rw-r--r--apps/kit/src/routes/(main)/+layout.svelte26
21 files changed, 511 insertions, 434 deletions
diff --git a/apps/kit/src/lib/components/alert.svelte b/apps/kit/src/lib/components/alert.svelte
index fa36a63..31e7357 100644
--- a/apps/kit/src/lib/components/alert.svelte
+++ b/apps/kit/src/lib/components/alert.svelte
@@ -3,13 +3,7 @@
import { createEventDispatcher } from "svelte";
import { onMount } from "svelte";
import { Temporal } from "temporal-polyfill";
- import {
- ExclamationTriangle,
- CheckCircle,
- InformationCircle,
- XCircle,
- XMark,
- } from "./icons";
+ import { ExclamationTriangleIcon, CheckCircleIcon, InformationCircleIcon, XCircleIcon, XMarkIcon } from "./icons";
const dispatch = createEventDispatcher();
const noCooldownSetting = "no-cooldown";
@@ -58,46 +52,40 @@
* Text is the button text
* Color is the optional tailwind color to used, the value is used in classes like bg-$color-50.
*/
- export let actions: Array<{ id: string; text: string; color?: string }> =
- [];
+ export let actions: Array<{ id: string; text: string; color?: string }> = [];
/**
* This value is set on a plain anchor tag without any svelte routing,
* listen to the on:rightLinkClick if you want to intercept the click without navigating
*/
export let rightLinkHref = "javascript:void(0)";
$: cooldownEnabled =
- id.indexOf(noCooldownSetting) === -1 &&
- closeable &&
- (closeableCooldown === "~" || parseInt(closeableCooldown) > 0);
+ id.indexOf(noCooldownSetting) === -1 && closeable && (closeableCooldown === "~" || parseInt(closeableCooldown) > 0);
/**
* Sets this alerts visibility state, when this is false it is removed from the dom using svelte a {#if} block.
*/
- export let visible =
- closeableCooldown === "~" || parseInt(closeableCooldown) > 0
- ? false
- : true;
+ export let visible = closeableCooldown === "~" || parseInt(closeableCooldown) > 0 ? false : true;
const cooldownStorageKey = "lastseen--" + id;
$: switch (type) {
case "info": {
colorClassPart = "blue";
- iconComponent = InformationCircle;
+ iconComponent = InformationCircleIcon;
break;
}
case "warning": {
colorClassPart = "yellow";
- iconComponent = ExclamationTriangle;
+ iconComponent = ExclamationTriangleIcon;
break;
}
case "error": {
colorClassPart = "red";
- iconComponent = XCircle;
+ iconComponent = XCircleIcon;
break;
}
case "success": {
colorClassPart = "green";
- iconComponent = CheckCircle;
+ iconComponent = CheckCircleIcon;
break;
}
}
@@ -105,15 +93,8 @@
function close() {
visible = false;
if (cooldownEnabled) {
- console.log(
- "Cooldown enabled for " + id + ", " + closeableCooldown === "~"
- ? "with an endless cooldown"
- : ""
- );
- localStorage.setItem(
- cooldownStorageKey,
- String(Temporal.Now.instant().epochSeconds)
- );
+ console.log("Cooldown enabled for " + id + ", " + closeableCooldown === "~" ? "with an endless cooldown" : "");
+ localStorage.setItem(cooldownStorageKey, String(Temporal.Now.instant().epochSeconds));
}
}
@@ -148,15 +129,8 @@
return;
}
- const lastSeen = Temporal.Instant.fromEpochSeconds(
- parseInt(localStorage.getItem(cooldownStorageKey) ?? "-1")
- );
- if (
- Temporal.Instant.compare(
- Temporal.Now.instant(),
- lastSeen.add({ seconds: parseInt(closeableCooldown) })
- ) === 1
- ) {
+ const lastSeen = Temporal.Instant.fromEpochSeconds(parseInt(localStorage.getItem(cooldownStorageKey) ?? "-1"));
+ if (Temporal.Instant.compare(Temporal.Now.instant(), lastSeen.add({ seconds: parseInt(closeableCooldown) })) === 1) {
console.log(
"Alert " +
id +
@@ -177,31 +151,19 @@
run_cooldown();
}
- if (
- closeable &&
- closeableCooldown &&
- id.indexOf(noCooldownSetting) !== -1
- ) {
+ if (closeable && closeableCooldown && id.indexOf(noCooldownSetting) !== -1) {
// TODO: This prints twice before shutting up as it should, in this example look at the only alert with closeableCooldown in alertsbook.
// Looks like svelte mounts three times and that my id is only set on the third. Not sure it does at all after logging the id onMount.
- console.error(
- "Alert cooldown does not work without specifying a unique id, related id: " +
- id
- );
+ console.error("Alert cooldown does not work without specifying a unique id, related id: " + id);
}
});
</script>
{#if visible}
- <div
- class="rounded-md bg-{colorClassPart}-50 p-4 {$$restProps.class ?? ''}"
- >
+ <div class="rounded-md bg-{colorClassPart}-50 p-4 {$$restProps.class ?? ''}">
<div class="flex">
<div class="flex-shrink-0">
- <svelte:component
- this={iconComponent}
- class="text-{colorClassPart}-400"
- />
+ <svelte:component this={iconComponent} class="text-{colorClassPart}-400" />
</div>
<div class="ml-3 text-sm w-full">
{#if !rightLinkText}
@@ -211,20 +173,14 @@
</h3>
{/if}
{#if message}
- <div
- class="{title
- ? 'mt-2'
- : ''} text-{colorClassPart}-700 justify-start"
- >
+ <div class="{title ? 'mt-2' : ''} text-{colorClassPart}-700 justify-start">
<p>
{@html message}
</p>
</div>
{/if}
{#if listItems?.length ?? 0}
- <ul
- class="list-disc space-y-1 pl-5 text-{colorClassPart}-700"
- >
+ <ul class="list-disc space-y-1 pl-5 text-{colorClassPart}-700">
{#each listItems as listItem}
<li>{listItem}</li>
{/each}
@@ -234,27 +190,19 @@
<div class="flex-1 md:flex md:justify-between">
<div>
{#if title}
- <h3
- class="font-medium text-{colorClassPart}-800"
- >
+ <h3 class="font-medium text-{colorClassPart}-800">
{title}
</h3>
{/if}
{#if message}
- <div
- class="{title
- ? 'mt-2'
- : ''} text-{colorClassPart}-700 justify-start"
- >
+ <div class="{title ? 'mt-2' : ''} text-{colorClassPart}-700 justify-start">
<p>
{@html message}
</p>
</div>
{/if}
{#if listItems?.length ?? 0}
- <ul
- class="list-disc space-y-1 pl-5 text-{colorClassPart}-700"
- >
+ <ul class="list-disc space-y-1 pl-5 text-{colorClassPart}-700">
{#each listItems as listItem}
<li>{listItem}</li>
{/each}
@@ -307,7 +255,7 @@
class="inline-flex rounded-md bg-{colorClassPart}-50 p-1.5 text-{colorClassPart}-500 hover:bg-{colorClassPart}-100 focus:outline-none focus:ring-2 focus:ring-{colorClassPart}-600 focus:ring-offset-2 focus:ring-offset-{colorClassPart}-50"
>
<span class="sr-only">Dismiss</span>
- <XMark />
+ <XMarkIcon />
</button>
</div>
</div>
diff --git a/apps/kit/src/lib/components/button.svelte b/apps/kit/src/lib/components/button.svelte
index 323c7ad..d345b37 100644
--- a/apps/kit/src/lib/components/button.svelte
+++ b/apps/kit/src/lib/components/button.svelte
@@ -4,7 +4,7 @@
</script>
<script lang="ts">
- import { Spinner } from "./icons";
+ import { SpinnerIcon } from "./icons";
export let kind = "primary" as ButtonKind;
export let size = "md" as ButtonSize;
@@ -54,18 +54,15 @@
$: switch (kind) {
case "secondary":
- kindClasses =
- "border-transparent text-teal-800 bg-teal-100 hover:bg-teal-200 focus:ring-teal-500";
+ kindClasses = "border-transparent text-teal-800 bg-teal-100 hover:bg-teal-200 focus:ring-teal-500";
spinnerTextClasses = "teal-800";
break;
case "primary":
- kindClasses =
- "border-transparent text-teal-900 bg-teal-300 hover:bg-teal-400 focus:ring-teal-500";
+ kindClasses = "border-transparent text-teal-900 bg-teal-300 hover:bg-teal-400 focus:ring-teal-500";
spinnerTextClasses = "text-teal-900";
break;
case "white":
- kindClasses =
- "border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-gray-400";
+ kindClasses = "border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-gray-400";
spinnerTextClasses = "text-gray-700";
break;
}
@@ -76,14 +73,12 @@
{...shared_props}
{href}
on:click
- class="{sizeClasses} {kindClasses} {loading
- ? 'disabled:'
- : ''} {$$restProps.class ?? ''} {fullWidth
+ class="{sizeClasses} {kindClasses} {loading ? 'disabled:' : ''} {$$restProps.class ?? ''} {fullWidth
? 'w-full justify-center'
: ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2"
>
{#if loading}
- <Spinner class={spinnerTextClasses + " " + spinnerMarginClasses} />
+ <SpinnerIcon class={spinnerTextClasses + " " + spinnerMarginClasses} />
{/if}
{text}
</a>
@@ -95,7 +90,7 @@
: ''} inline-flex items-center border font-medium rounded shadow-sm focus:outline-none focus:ring-2"
>
{#if loading}
- <Spinner class={spinnerTextClasses + " " + spinnerMarginClasses} />
+ <SpinnerIcon class={spinnerTextClasses + " " + spinnerMarginClasses} />
{/if}
{text}
</button>
diff --git a/apps/kit/src/lib/components/icons/bars-3-center-left.svelte b/apps/kit/src/lib/components/icons/bars-3-center-left.svelte
new file mode 100644
index 0000000..785ece3
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/bars-3-center-left.svelte
@@ -0,0 +1,15 @@
+<svg
+ class="h-6 w-6 {$$restProps.class ?? ''}"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ aria-hidden="true"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/icons/calendar.svelte b/apps/kit/src/lib/components/icons/calendar.svelte
new file mode 100644
index 0000000..e0053ee
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/calendar.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="w-6 h-6 {$$restProps.class ?? ''}"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/icons/chevron-up-down.svelte b/apps/kit/src/lib/components/icons/chevron-up-down.svelte
new file mode 100644
index 0000000..c07aed5
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/chevron-up-down.svelte
@@ -0,0 +1,13 @@
+<svg
+ class="h-5 w-5 {$$restProps.class ?? ''}"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 20 20"
+ fill="currentColor"
+ aria-hidden="true"
+>
+ <path
+ fill-rule="evenodd"
+ d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z"
+ clip-rule="evenodd"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/icons/folder-open.svelte b/apps/kit/src/lib/components/icons/folder-open.svelte
new file mode 100644
index 0000000..409c8e2
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/folder-open.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="w-6 h-6 {$$restProps.class ?? ''}"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/icons/index.ts b/apps/kit/src/lib/components/icons/index.ts
index e846dc4..8c24873 100644
--- a/apps/kit/src/lib/components/icons/index.ts
+++ b/apps/kit/src/lib/components/icons/index.ts
@@ -3,25 +3,39 @@ import MenuIcon from "./menu.svelte";
import AdjustmentsIcon from "./adjustments.svelte";
import DatabaseIcon from "./database.svelte";
import HomeIcon from "./home.svelte";
-import InformationCircle from "./information-circle.svelte";
-import ExclamationTriangle from "./exclamation-triangle.svelte";
-import XCircle from "./x-circle.svelte";
-import CheckCircle from "./check-circle.svelte";
-import XMark from "./x-mark.svelte";
-import Spinner from "./spinner.svelte";
-import ExclamationCircle from "./exclamation-circle.svelte";
+import InformationCircleIcon from "./information-circle.svelte";
+import ExclamationTriangleIcon from "./exclamation-triangle.svelte";
+import XCircleIcon from "./x-circle.svelte";
+import CheckCircleIcon from "./check-circle.svelte";
+import XMarkIcon from "./x-mark.svelte";
+import SpinnerIcon from "./spinner.svelte";
+import ExclamationCircleIcon from "./exclamation-circle.svelte";
+import ChevronUpDownIcon from "./chevron-up-down.svelte";
+import MagnifyingGlassIcon from "./magnifying-glass.svelte";
+import Bars3CenterLeftIcon from "./bars-3-center-left.svelte";
+import CalendarIcon from "./calendar.svelte";
+import FolderOpenIcon from "./folder-open.svelte";
+import MegaphoneIcon from "./megaphone.svelte";
+import QueueListIcon from "./queue-list.svelte";
export {
+ QueueListIcon,
+ FolderOpenIcon,
+ MegaphoneIcon,
+ CalendarIcon,
+ Bars3CenterLeftIcon,
+ MagnifyingGlassIcon,
+ ChevronUpDownIcon,
XIcon,
MenuIcon,
HomeIcon,
DatabaseIcon,
AdjustmentsIcon,
- InformationCircle,
- ExclamationTriangle,
- ExclamationCircle,
- XCircle,
- CheckCircle,
- XMark,
- Spinner
+ InformationCircleIcon,
+ ExclamationTriangleIcon,
+ ExclamationCircleIcon,
+ XCircleIcon,
+ CheckCircleIcon,
+ XMarkIcon,
+ SpinnerIcon
} \ No newline at end of file
diff --git a/apps/kit/src/lib/components/icons/magnifying-glass.svelte b/apps/kit/src/lib/components/icons/magnifying-glass.svelte
new file mode 100644
index 0000000..f8fdb6e
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/magnifying-glass.svelte
@@ -0,0 +1,13 @@
+<svg
+ class="h-5 w-5 {$$restProps.class ?? ''}"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 20 20"
+ fill="currentColor"
+ aria-hidden="true"
+>
+ <path
+ fill-rule="evenodd"
+ d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
+ clip-rule="evenodd"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/icons/megaphone.svelte b/apps/kit/src/lib/components/icons/megaphone.svelte
new file mode 100644
index 0000000..7ada5f3
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/megaphone.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="w-6 h-6 {$$restProps.class ?? ''}"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M10.34 15.84c-.688-.06-1.386-.09-2.09-.09H7.5a4.5 4.5 0 110-9h.75c.704 0 1.402-.03 2.09-.09m0 9.18c.253.962.584 1.892.985 2.783.247.55.06 1.21-.463 1.511l-.657.38c-.551.318-1.26.117-1.527-.461a20.845 20.845 0 01-1.44-4.282m3.102.069a18.03 18.03 0 01-.59-4.59c0-1.586.205-3.124.59-4.59m0 9.18a23.848 23.848 0 018.835 2.535M10.34 6.66a23.847 23.847 0 008.835-2.535m0 0A23.74 23.74 0 0018.795 3m.38 1.125a23.91 23.91 0 011.014 5.395m-1.014 8.855c-.118.38-.245.754-.38 1.125m.38-1.125a23.91 23.91 0 001.014-5.395m0-3.46c.495.413.811 1.035.811 1.73 0 .695-.316 1.317-.811 1.73m0-3.46a24.347 24.347 0 010 3.46"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/icons/queue-list.svelte b/apps/kit/src/lib/components/icons/queue-list.svelte
new file mode 100644
index 0000000..6148394
--- /dev/null
+++ b/apps/kit/src/lib/components/icons/queue-list.svelte
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="w-6 h-6 {$$restProps.class ?? ''}"
+>
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.625 4.5h12.75a1.875 1.875 0 010 3.75H5.625a1.875 1.875 0 010-3.75z"
+ />
+</svg>
diff --git a/apps/kit/src/lib/components/input.svelte b/apps/kit/src/lib/components/input.svelte
index 6063fe4..999c565 100644
--- a/apps/kit/src/lib/components/input.svelte
+++ b/apps/kit/src/lib/components/input.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
import { random_string } from "$lib/helpers";
- import { ExclamationCircle } from "./icons";
+ import { ExclamationCircleIcon } from "./icons";
export let label: string | undefined = undefined;
export let type: string = "text";
@@ -28,12 +28,10 @@
required: required || null,
} as any;
$: hasBling = icon || addon || errorText;
- const defaultColorClass =
- "border-gray-300 focus:border-teal-500 focus:ring-teal-500";
+ const defaultColorClass = "border-gray-300 focus:border-teal-500 focus:ring-teal-500";
let colorClass = defaultColorClass;
$: if (errorText) {
- colorClass =
- "placeholder-red-300 focus:border-red-500 focus:outline-none focus:ring-red-500 text-red-900 pr-10 border-red-300";
+ colorClass = "placeholder-red-300 focus:border-red-500 focus:outline-none focus:ring-red-500 text-red-900 pr-10 border-red-300";
} else {
colorClass = defaultColorClass;
}
@@ -45,23 +43,13 @@
<div class={wrapperClass}>
{#if label && !cornerHint && !hideLabel}
- <label
- for={id}
- class={hideLabel
- ? "sr-only"
- : "block text-sm font-medium text-gray-700"}
- >
+ <label for={id} class={hideLabel ? "sr-only" : "block text-sm font-medium text-gray-700"}>
{label}
</label>
{:else if cornerHint && !hideLabel}
<div class="flex justify-between">
{#if label}
- <label
- for={id}
- class={hideLabel
- ? "sr-only"
- : "block text-sm font-medium text-gray-700"}
- >
+ <label for={id} class={hideLabel ? "sr-only" : "block text-sm font-medium text-gray-700"}>
{label}
</label>
{/if}
@@ -70,24 +58,13 @@
</span>
</div>
{/if}
- <div
- class="mt-1 {hasBling ? 'relative rounded-md' : ''} {addon
- ? 'flex'
- : ''}"
- >
+ <div class="mt-1 {hasBling ? 'relative rounded-md' : ''} {addon ? 'flex' : ''}">
{#if icon}
- <div
- class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
- >
- <svelte:component
- this={icon}
- class={errorText ? "text-red-500" : "text-gray-400"}
- />
+ <div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
+ <svelte:component this={icon} class={errorText ? "text-red-500" : "text-gray-400"} />
</div>
{:else if addon}
- <div
- class="inline-flex items-center rounded-l-md border border-r-0 border-gray-300 bg-gray-50 px-3 text-gray-500 sm:text-sm"
- >
+ <div class="inline-flex items-center rounded-l-md border border-r-0 border-gray-300 bg-gray-50 px-3 text-gray-500 sm:text-sm">
<span class="text-gray-500 sm:text-sm">{addon}</span>
</div>
{/if}
@@ -97,19 +74,16 @@
{id}
{...attributes}
bind:value
- class="block w-full rounded-md shadow-sm sm:text-sm {colorClass} {disabled
- ? 'disabled:cursor-not-allowed disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500'
- : ''}
- {addon ? 'min-w-0 flex-1 rounded-none rounded-r-md' : ''} {icon
- ? 'pl-10'
- : ''}"
+ class="block w-full rounded-md shadow-sm sm:text-sm
+ {colorClass}
+ {disabled ? 'disabled:cursor-not-allowed disabled:border-gray-200 disabled:bg-gray-50 disabled:text-gray-500' : ''}
+ {addon ? 'min-w-0 flex-1 rounded-none rounded-r-md' : ''}
+ {icon ? 'pl-10' : ''}"
{placeholder}
/>
{#if errorText}
- <div
- class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3"
- >
- <ExclamationCircle class="text-red-500" />
+ <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
+ <ExclamationCircleIcon class="text-red-500" />
</div>
{/if}
</div>
diff --git a/apps/kit/src/lib/components/locale-switcher.svelte b/apps/kit/src/lib/components/locale-switcher.svelte
index 39d6168..1f9eb37 100644
--- a/apps/kit/src/lib/components/locale-switcher.svelte
+++ b/apps/kit/src/lib/components/locale-switcher.svelte
@@ -1,51 +1,32 @@
<script lang="ts">
- import {browser} from "$app/environment";
- import {page} from "$app/stores";
- import {setLocale, locale} from "$lib/i18n/i18n-svelte";
- import type {Locales} from "$lib/i18n/i18n-types";
- import {locales} from "$lib/i18n/i18n-util";
- import {loadLocaleAsync} from "$lib/i18n/i18n-util.async";
+ import { browser } from "$app/environment";
+ import { page } from "$app/stores";
+ import { setLocale, locale } from "$lib/i18n/i18n-svelte";
+ import type { Locales } from "$lib/i18n/i18n-types";
+ import { locales } from "$lib/i18n/i18n-util";
+ import { loadLocaleAsync } from "$lib/i18n/i18n-util.async";
- const switchLocale = async (
- newLocale: Locales,
- updateHistoryState = true,
- ) => {
+ const switchLocale = async (newLocale: Locales) => {
if (!newLocale || $locale === newLocale) return;
-
- // load new dictionary from server
await loadLocaleAsync(newLocale);
-
- // select locale
setLocale(newLocale);
-
- // update `lang` attribute
document.querySelector("html")?.setAttribute("lang", newLocale);
-
- //TODO set cookie that persists the locale
};
- // update locale when navigating via browser back/forward buttons
- const handlePopStateEvent = async ({state}: PopStateEvent) =>
- switchLocale(state.locale, false);
-
- // update locale when page store changes
$: if (browser) {
- const lang = $page.params.lang as Locales;
- switchLocale(lang, false);
+ switchLocale($page.params.lang as Locales);
}
</script>
-<svelte:window on:popstate={handlePopStateEvent}/>
-
<ul>
- {#each locales as l}
+ {#each locales as aLocale}
<li>
<button
- type="button"
- class:active={l === $locale}
- on:click={() => switchLocale(l)}
+ type="button"
+ class:active={aLocale === $locale}
+ on:click={() => switchLocale(aLocale)}
>
- {l}
+ {aLocale}
</button>
</li>
{/each}
diff --git a/apps/kit/src/routes/(main)/(app)/+layout.svelte b/apps/kit/src/routes/(main)/(app)/+layout.svelte
index b69341c..6660c53 100644
--- a/apps/kit/src/routes/(main)/(app)/+layout.svelte
+++ b/apps/kit/src/routes/(main)/(app)/+layout.svelte
@@ -1,283 +1,297 @@
<script lang="ts">
- import LL from "$lib/i18n/i18n-svelte";
- import {
- Dialog,
- TransitionChild,
- TransitionRoot,
- } from "@rgossiaux/svelte-headlessui";
- import {
- MenuIcon,
- HomeIcon,
- DatabaseIcon,
- AdjustmentsIcon,
- } from "$lib/components/icons";
+ import {
+ ChevronUpDownIcon,
+ MagnifyingGlassIcon,
+ Bars3CenterLeftIcon,
+ XMarkIcon,
+ HomeIcon,
+ MegaphoneIcon,
+ FolderOpenIcon,
+ QueueListIcon,
+ CalendarIcon,
+ } from "$lib/components/icons";
+ import { Dialog, Menu, MenuButton, MenuItem, MenuItems, Transition, TransitionChild, TransitionRoot } from "@rgossiaux/svelte-headlessui";
+ import { DialogPanel } from "@developermuch/dev-svelte-headlessui";
+ import type { ISession } from "$lib/models/ISession";
+ import { Input } from "$lib/components";
+ import { end_session } from "$lib/session";
+ import { goto } from "$app/navigation";
+ import { page } from "$app/stores";
- let online = true;
- let sidebarIsOpen = false;
- const username = "dumb";
+ const session = {
+ profile: {
+ username: "Brukernavn",
+ displayName: "epost@adresse.no",
+ },
+ } as ISession;
- const navigations = [
- {
- name: "Home",
- icon: HomeIcon,
- },
- {
- name: "Data",
- icon: DatabaseIcon,
- },
- {
- name: "Settings",
- icon: AdjustmentsIcon,
- },
- ];
+ let sidebarOpen = false;
+ let sidebarSearchValue: string | undefined;
+
+ function signOut() {
+ end_session(() => goto("/sign-in"));
+ }
+
+ const navigationItems = [
+ {
+ href: "/home",
+ name: "Home",
+ icon: HomeIcon,
+ },
+ {
+ href: "/projects",
+ name: "Projects",
+ icon: CalendarIcon,
+ },
+ {
+ href: "/tickets",
+ name: "Tickets",
+ icon: MegaphoneIcon,
+ },
+ {
+ href: "/todo",
+ name: "Todo",
+ icon: QueueListIcon,
+ },
+ {
+ href: "/wiki",
+ name: "Wiki",
+ icon: FolderOpenIcon,
+ },
+ ];
</script>
-<svelte:window bind:online />
-{#if !online}
- <div class="bg-yellow-50 border-l-4 border-yellow-400 p-4">
- <div class="flex">
- <div class="flex-shrink-0">
- <svg
- class="h-5 w-5 text-yellow-400"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
- clip-rule="evenodd"
- />
- </svg>
- </div>
- <div class="ml-3">
- <p class="text-sm text-yellow-700">
- You seem to be offline, please check your internet
- connection.
- </p>
- </div>
- </div>
- </div>
-{/if}
-<div class="h-full flex">
- <TransitionRoot show={sidebarIsOpen}>
- <Dialog
- class="relative z-40 lg:hidden"
- on:close={() => (sidebarIsOpen = !sidebarIsOpen)}
+<div class="min-h-full">
+ <!-- Mobile sidebar -->
+ <TransitionRoot show={sidebarOpen}>
+ <Dialog as="div" class="relative z-40 lg:hidden" on:close={() => (sidebarOpen = false)}>
+ <TransitionChild
+ as="div"
+ enter="transition-opacity ease-linear duration-300"
+ enterFrom="opacity-0"
+ enterTo="opacity-100"
+ leave="transition-opacity ease-linear duration-300"
+ leaveFrom="opacity-100"
+ leaveTo="opacity-0"
+ >
+ <div class="fixed inset-0 bg-gray-600 bg-opacity-75" />
+ </TransitionChild>
+
+ <div class="fixed inset-0 z-40 flex">
+ <TransitionChild
+ as="div"
+ enter="transition ease-in-out duration-300 transform"
+ enterFrom="-translate-x-full"
+ enterTo="translate-x-0"
+ leave="transition ease-in-out duration-300 transform"
+ leaveFrom="translate-x-0"
+ leaveTo="-translate-x-full"
>
+ <DialogPanel class="relative flex w-full max-w-xs flex-1 flex-col bg-white pt-5 pb-4">
<TransitionChild
- enter="transition-opacity ease-linear duration-300"
- enterFrom="opacity-0"
- enterTo="opacity-100"
- leave="transition-opacity ease-linear duration-300"
- leaveFrom="opacity-100"
- leaveTo="opacity-0"
+ as="div"
+ enter="ease-in-out duration-300"
+ enterFrom="opacity-0"
+ enterTo="opacity-100"
+ leave="ease-in-out duration-300"
+ leaveFrom="opacity-100"
+ leaveTo="opacity-0"
>
- <div class="fixed inset-0 bg-gray-600 bg-opacity-75" />
- </TransitionChild>
-
- <div class="fixed inset-0 flex z-40">
- <TransitionChild
- enter="transition ease-in-out duration-300 transform"
- enterFrom="-translate-x-full"
- enterTo="translate-x-0"
- leave="transition ease-in-out duration-300 transform"
- leaveFrom="translate-x-0"
- leaveTo="-translate-x-full"
+ <div class="absolute top-0 right-0 -mr-12 pt-2">
+ <button
+ type="button"
+ class="ml-1 flex h-10 w-10 items-center justify-center rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
+ on:click={() => (sidebarOpen = false)}
>
- <!-- <DialogPanel
- class="relative flex-1 flex flex-col max-w-xs w-full bg-white focus:outline-none"
+ <span class="sr-only">Close sidebar</span>
+ <XMarkIcon class="text-white" aria-hidden="true" />
+ </button>
+ </div>
+ </TransitionChild>
+ <div class="mt-5 h-0 flex-1 overflow-y-auto">
+ <nav class="px-2">
+ <div class="space-y-1">
+ {#each navigationItems as item}
+ {@const current = $page.url.pathname.startsWith(item.href)}
+ <a
+ href={item.href}
+ aria-current={current ? "page" : undefined}
+ class="group flex items-center px-2 py-2 text-base leading-5 font-medium rounded-md
+ {current ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900 hover:bg-gray-50'}"
>
- <TransitionChild
- enter="ease-in-out duration-300"
- enterFrom="opacity-0"
- enterTo="opacity-100"
- leave="ease-in-out duration-300"
- leaveFrom="opacity-100"
- leaveTo="opacity-0"
- >
- <div class="absolute top-0 right-0 -mr-12 pt-2">
- <button
- type="button"
- class="ml-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
- on:click={() => (sidebarIsOpen = false)}
- >
- <span class="sr-only">Close sidebar</span>
- <XIcon
- class="text-white"
- aria-hidden="true"
- />
- </button>
- </div>
- </TransitionChild>
- <div class="flex-1 h-0 pt-5 pb-4 overflow-y-auto">
- <div class="flex-shrink-0 flex items-center px-4">
- <img
- class="h-8 w-auto"
- src="https://tailwindui.com/img/logos/workflow-mark.svg?color=indigo&shade=600"
- alt="Workflow"
- />
- </div>
- <nav aria-label="Sidebar" class="mt-5">
- <div class="px-2 space-y-1">
- {#each navigations as item (item.name)}
- <a
- href={item.href}
- class="{item.current
- ? 'bg-gray-100 text-gray-900'
- : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'} group flex items-center px-2 py-2 text-base font-medium rounded-md"
- >
- <svelte:component
- this={item.icon}
- class="{item.current
- ? 'text-gray-500'
- : 'text-gray-400 group-hover:text-gray-500'} mr-4 h-6 w-6"
- aria-hidden="true"
- />
- {item.name}
- </a>
- {/each}
- </div>
- </nav>
- </div>
- <div
- class="flex-shrink-0 flex border-t border-gray-200 p-4"
- >
- <a href="#" class="flex-shrink-0 group block">
- <div class="flex items-center">
- <div>
- <img
- class="inline-block h-10 w-10 rounded-full"
- src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80"
- alt=""
- />
- </div>
- <div class="ml-3">
- <p
- class="text-base font-medium text-gray-700 group-hover:text-gray-900"
- >
- {username}
- </p>
- <p
- class="text-sm font-medium text-gray-500 group-hover:text-gray-700"
- >
- {$LL.nav.usermenu.profileTitle()}
- </p>
- </div>
- </div>
- </a>
- </div>
- </DialogPanel> -->
- </TransitionChild>
- <div class="flex-shrink-0 w-14" aria-hidden="true">
- <!--{/* Force sidebar to shrink to fit close icon */}-->
+ <svelte:component
+ this={item.icon}
+ class="mr-3 flex-shrink-0 h-6 w-6 {current ? 'text-gray-500' : 'text-gray-400 group-hover:text-gray-500'}"
+ aria-hidden="true"
+ />
+ {item.name}
+ </a>
+ {/each}
</div>
+ </nav>
</div>
- </Dialog>
- </TransitionRoot>
+ </DialogPanel>
+ </TransitionChild>
+ <div class="w-14 flex-shrink-0" aria-hidden="true">
+ <!-- Dummy element to force sidebar to shrink to fit close icon -->
+ </div>
+ </div>
+ </Dialog>
+ </TransitionRoot>
- <!--{/* Static sidebar for desktop */}-->
- <div class="hidden lg:flex lg:flex-shrink-0">
- <div class="flex flex-col w-64">
- <!--{/* Sidebar component, swap this element with another sidebar if you like */}-->
- <div
- class="flex-1 flex flex-col min-h-0 border-r border-gray-200 bg-gray-100"
- >
- <div class="flex-1 flex flex-col pt-5 pb-4 overflow-y-auto">
- <div class="flex items-center flex-shrink-0 px-4">
- <img
- class="h-8 w-auto"
- src="https://tailwindui.com/img/logos/workflow-mark.svg?color=indigo&shade=600"
- alt="Workflow"
- />
- </div>
- <nav class="mt-5 flex-1" aria-label="Sidebar">
- <div class="px-2 space-y-1">
- {#each navigations as item (item.name)}
- <a
- key={item.name}
- href={item.href}
- class="{item.current
- ? 'bg-gray-200 text-gray-900'
- : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'} group flex items-center px-2 py-2 text-sm font-medium rounded-md"
- >
- <svelte:component
- this={item.icon}
- class="{item.current
- ? 'text-gray-500'
- : 'text-gray-400 group-hover:text-gray-500'} mr-3 h-6 w-6"
- aria-hidden="true"
- />
- {item.name}
- </a>
- {/each}
- </div>
- </nav>
- </div>
- <div class="flex-shrink-0 flex border-t border-gray-200 p-4">
- <a href="#" class="flex-shrink-0 w-full group block">
- <div class="flex items-center">
- <div>
- <img
- class="inline-block h-9 w-9 rounded-full"
- src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=256&h=256&q=80"
- alt=""
- />
- </div>
- <div class="ml-3">
- <p
- class="text-base font-medium text-gray-700 group-hover:text-gray-900"
- >
- {username}
- </p>
- <p
- class="text-sm font-medium text-gray-500 group-hover:text-gray-700"
- >
- {$LL.nav.usermenu.profileTitle()}
- </p>
- </div>
- </div>
- </a>
- </div>
+ <!-- Static sidebar for desktop -->
+ <div class="hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64 lg:flex-col lg:border-r lg:border-gray-200 lg:bg-gray-100 lg:pb-4">
+ <div class="flex h-0 flex-1 p-3 flex-col overflow-y-auto">
+ <!-- User account dropdown -->
+ <Menu class="relative inline-block text-left">
+ <MenuButton
+ class="group w-full rounded-md bg-gray-100 px-3.5 py-2 text-left text-sm font-medium text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 focus:ring-offset-gray-100"
+ >
+ <span class="flex w-full items-center justify-between">
+ <span class="flex min-w-0 items-center justify-between space-x-3">
+ <span class="flex min-w-0 flex-1 flex-col">
+ <span class="truncate text-sm font-medium text-gray-900">
+ {session.profile.username}
+ </span>
+ <span class="truncate text-sm text-gray-500">{session.profile.displayName}</span>
+ </span>
+ </span>
+ <ChevronUpDownIcon class="flex-shrink-0 text-gray-400 group-hover:text-gray-500" aria-hidden="true" />
+ </span>
+ </MenuButton>
+ <Transition
+ leave="transition ease-in duration-75"
+ enter="transition ease-out duration-100"
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ as="div"
+ >
+ <MenuItems
+ class="absolute right-0 left-0 z-10 mt-1 origin-top divide-y divide-gray-200 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
+ >
+ <div class="py-1">
+ <MenuItem>
+ <a href="/profile" class="text-gray-700 block px-4 py-2 text-sm hover:text-gray-900 hover:bg-gray-100"> View profile </a>
+ </MenuItem>
+ <MenuItem>
+ <a href="/settings" class="text-gray-700 block px-4 py-2 text-sm hover:text-gray-900 hover:bg-gray-100"> Settings </a>
+ </MenuItem>
</div>
+ <div class="py-1">
+ <MenuItem>
+ <span
+ on:click={() => signOut()}
+ class="text-gray-700 block px-4 py-2 text-sm hover:bg-red-200 hover:text-red-900 cursor-pointer"
+ >
+ Sign out
+ </span>
+ </MenuItem>
+ </div>
+ </MenuItems>
+ </Transition>
+ </Menu>
+ <!-- Sidebar Search -->
+ <div class="mt-3">
+ <label for="search" class="sr-only">Search</label>
+ <div class="relative mt-1 rounded-md shadow-sm">
+ <Input type="search" name="search" icon={MagnifyingGlassIcon} placeholder="Search" bind:value={sidebarSearchValue} />
</div>
- </div>
- <div class="flex flex-col min-w-0 flex-1 overflow-hidden">
- <div class="lg:hidden">
- <div
- class="flex items-center justify-between bg-gray-50 border-b border-gray-200 px-4 py-1.5"
+ </div>
+ <!-- Navigation -->
+ <nav class="mt-5">
+ <div class="space-y-1">
+ {#each navigationItems as item}
+ {@const current = $page.url.pathname.startsWith(item.href)}
+ <a
+ href={item.href}
+ aria-current={current ? "page" : undefined}
+ class="group flex items-center px-2 py-2 text-base leading-5 font-medium rounded-md
+ {current ? 'bg-gray-200 text-gray-900' : 'text-gray-700 hover:text-gray-900 hover:bg-gray-50'}"
>
- <div>
- <button
- type="button"
- class="-mr-3 h-12 w-12 inline-flex items-center justify-center rounded-md text-gray-500 hover:text-gray-900"
- on:click={() => (sidebarIsOpen = true)}
- >
- <span class="sr-only">Open sidebar</span>
- <MenuIcon aria-hidden="true" />
- </button>
- </div>
+ <svelte:component
+ this={item.icon}
+ class="mr-3 flex-shrink-0 h-6 w-6 {current ? 'text-gray-500' : 'text-gray-400 group-hover:text-gray-500'}"
+ aria-hidden="true"
+ />
+ {item.name}
+ </a>
+ {/each}
+ </div>
+ </nav>
+ </div>
+ </div>
+
+ <!-- Main column -->
+ <div class="flex flex-col lg:pl-64">
+ <!-- Search header -->
+ <div class="sticky top-0 z-10 flex h-16 flex-shrink-0 border-b border-gray-200 bg-white lg:hidden">
+ <button
+ type="button"
+ class="border-r border-gray-200 px-4 text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-teal-500 lg:hidden"
+ on:click={() => (sidebarOpen = true)}
+ >
+ <span class="sr-only">Open sidebar</span>
+ <Bars3CenterLeftIcon aria-hidden="true" />
+ </button>
+ <div class="flex flex-1 justify-between px-4 sm:px-6 lg:px-8">
+ <div class="flex flex-1">
+ <form class="flex w-full md:ml-0" action="#" method="GET">
+ <label for="search-field" class="sr-only">Search</label>
+ <div class="relative w-full text-gray-400 focus-within:text-gray-600">
+ <Input
+ bind:value={sidebarSearchValue}
+ icon={MagnifyingGlassIcon}
+ id="search-field"
+ name="search-field"
+ placeholder="Search"
+ type="search"
+ />
</div>
+ </form>
</div>
- <div class="flex-1 relative z-0 flex overflow-hidden">
- <main
- class="flex-1 relative z-0 overflow-y-auto focus:outline-none"
- >
- <!--
- MAIN CONTENT
- -->
- <slot />
- </main>
- <aside
- class="hidden relative xl:flex xl:flex-col flex-shrink-0 w-96 border-l border-gray-200 overflow-y-auto"
+ <div class="flex items-center">
+ <!-- Profile dropdown -->
+ <Menu as="div" class="relative ml-3">
+ <div>
+ <MenuButton
+ class="flex max-w-xs items-center rounded-full bg-white text-sm focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2"
+ >
+ <span class="sr-only">Open user menu</span>
+ </MenuButton>
+ </div>
+ <Transition
+ enterFrom="transform opacity-0 scale-95"
+ enterTo="transform opacity-100 scale-100"
+ leaveFrom="transform opacity-100 scale-100"
+ leaveTo="transform opacity-0 scale-95"
+ as="div"
>
- <!--{/* Start secondary column (hidden on smaller screens) */}
- <div class="absolute inset-0 py-6 px-4 sm:px-6 lg:px-8">
- <div class="h-full border-2 border-gray-200 border-dashed rounded-lg" />
+ <MenuItems
+ class="absolute right-0 z-10 mt-2 w-48 origin-top-right divide-y divide-gray-200 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
+ >
+ <div class="py-1">
+ <MenuItem>
+ <a href="/profile" class="text-gray-700 block px-4 py-2 text-sm"> View profile </a>
+ </MenuItem>
+ <MenuItem>
+ <a href="/settings" class="text-gray-700 block px-4 py-2 text-sm hover:text-gray-900 hover:bg-gray-100"> Settings </a>
+ </MenuItem>
+ <div class="py-1">
+ <MenuItem>
+ <span on:click={() => signOut()} class="text-gray-700 block px-4 py-2 text-sm"> Sign out </span>
+ </MenuItem>
+ </div>
</div>
- {/* End secondary column */}-->
- </aside>
+ </MenuItems>
+ </Transition>
+ </Menu>
</div>
+ </div>
</div>
+ <main class="flex-1">
+ <slot />
+ </main>
+ </div>
</div>
diff --git a/apps/kit/src/routes/(main)/(app)/org/+page.svelte b/apps/kit/src/routes/(main)/(app)/org/+page.svelte
new file mode 100644
index 0000000..429ec25
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/org/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>$ORGNAME</h1>
diff --git a/apps/kit/src/routes/(main)/(app)/profile/+page.svelte b/apps/kit/src/routes/(main)/(app)/profile/+page.svelte
new file mode 100644
index 0000000..7c6eb3e
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/profile/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>Hi, Ivar</h1>
diff --git a/apps/kit/src/routes/(main)/(app)/projects/+page.svelte b/apps/kit/src/routes/(main)/(app)/projects/+page.svelte
new file mode 100644
index 0000000..6413e1d
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/projects/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>Projects</h1>
diff --git a/apps/kit/src/routes/(main)/(app)/settings/+page.svelte b/apps/kit/src/routes/(main)/(app)/settings/+page.svelte
new file mode 100644
index 0000000..ae6d403
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/settings/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>Settings</h1>
diff --git a/apps/kit/src/routes/(main)/(app)/tickets/+page.svelte b/apps/kit/src/routes/(main)/(app)/tickets/+page.svelte
new file mode 100644
index 0000000..2a4792b
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/tickets/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>Tickets</h1>
diff --git a/apps/kit/src/routes/(main)/(app)/todo/+page.svelte b/apps/kit/src/routes/(main)/(app)/todo/+page.svelte
new file mode 100644
index 0000000..e29f263
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/todo/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>Todo</h1>
diff --git a/apps/kit/src/routes/(main)/(app)/wiki/+page.svelte b/apps/kit/src/routes/(main)/(app)/wiki/+page.svelte
new file mode 100644
index 0000000..1762d43
--- /dev/null
+++ b/apps/kit/src/routes/(main)/(app)/wiki/+page.svelte
@@ -0,0 +1,4 @@
+<script lang="ts">
+</script>
+
+<h1>Wiki</h1>
diff --git a/apps/kit/src/routes/(main)/+layout.svelte b/apps/kit/src/routes/(main)/+layout.svelte
index 9787e17..5354f02 100644
--- a/apps/kit/src/routes/(main)/+layout.svelte
+++ b/apps/kit/src/routes/(main)/+layout.svelte
@@ -3,9 +3,35 @@
import { setLocale } from "$lib/i18n/i18n-svelte";
import type { LayoutData } from "./$types";
+ let online = true;
export let data: LayoutData;
setLocale(data.locale);
</script>
+<svelte:window bind:online />
+{#if !online}
+ <div class="bg-yellow-50 relative z-50 border-yellow-400 p-4">
+ <div class="flex">
+ <div class="flex-shrink-0">
+ <svg
+ class="h-5 w-5 text-yellow-400"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 20 20"
+ fill="currentColor"
+ aria-hidden="true"
+ >
+ <path
+ fill-rule="evenodd"
+ d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
+ clip-rule="evenodd"
+ />
+ </svg>
+ </div>
+ <div class="ml-3">
+ <p class="text-sm text-yellow-700">You seem to be offline, please check your internet connection.</p>
+ </div>
+ </div>
+ </div>
+{/if}
<slot />