Sanitize lib paths

This commit is contained in:
nemunaire 2022-10-15 11:12:51 +02:00
commit e9a906fbfb
43 changed files with 68 additions and 66 deletions

View file

@ -0,0 +1,76 @@
<script>
import { page } from '$app/stores';
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import { actions } from '$lib/stores/actions';
export let flush = false;
export { className as class };
let className = '';
let refreshInProgress = false;
function refresh_actions() {
refreshInProgress = true;
actions.refresh().then(() => {
refreshInProgress = false;
});
}
</script>
<div class="d-flex justify-content-between align-items-center" class:px-2={flush}>
<h2>
Actions
</h2>
<div>
{#if !flush}
<Button
href="routines/actions"
color="outline-info"
size="sm"
>
<Icon name="pencil" />
</Button>
{/if}
<Button
color="outline-dark"
size="sm"
title="Rafraîchir la liste des actions"
on:click={refresh_actions}
disabled={refreshInProgress}
>
{#if !refreshInProgress}
<Icon name="arrow-clockwise" />
{:else}
<Spinner color="dark" size="sm" />
{/if}
</Button>
</div>
</div>
<div class="list-group {className}" class:list-group-flush={flush}>
{#if $actions.list}
{#each $actions.list as action (action.id)}
<a
href="routines/actions/{action.id}"
class="list-group-item list-group-item-action"
class:active={$page.url.pathname.indexOf('/actions/') !== -1 && $page.params.aid == action.id}
aria-current="true"
>
<span class:fw-bold={action.enabled}>{action.name}</span>
</a>
{/each}
{:else}
{#await actions.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{:then}
test
{/await}
{/if}
</div>

View file

@ -0,0 +1,53 @@
<script>
import { page } from '$app/stores';
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import DateRangeFormat from '$lib/components/DateRangeFormat.svelte';
import { alarmsExceptions } from '$lib/stores/alarmexceptions';
export let flush = false;
</script>
<div class="d-flex justify-content-between align-items-center" class:mx-2={flush}>
<h2>
Exceptions
</h2>
<Button
href="alarms/exceptions/new"
color="outline-primary"
size="sm"
class="float-end {($page.params.kind === 'exceptions' && $page.url.pathname.endsWith('/new'))?'active':''}"
>
<Icon name="plus-lg" />
</Button>
</div>
<div class="text-center">
{#if $alarmsExceptions.list !== null}
{#if $alarmsExceptions.list.length}
<div class="list-group" class:list-group-flush={flush}>
{#each $alarmsExceptions.list as alarm (alarm.id)}
<a
href="alarms/exceptions/{alarm.id}"
class="list-group-item list-group-item-action"
class:active={$page.params.kind === "exceptions" && $page.params.aid === alarm.id}
>
Du <DateRangeFormat startDate={alarm._start()} endDate={alarm._end()} dateStyle="long" />
</a>
{/each}
</div>
{:else}
<p class="fst-italic">Pas d'exception programmée</p>
{/if}
{:else}
{#await alarmsExceptions.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{/await}
{/if}
</div>

View file

@ -0,0 +1,53 @@
<script>
import { page } from '$app/stores';
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import { weekdayStr } from '$lib/alarmrepeated';
import { alarmsRepeated } from '$lib/stores/alarmrepeated';
export let flush = false;
</script>
<div class="d-flex justify-content-between align-items-center" class:mx-2={flush}>
<h2>
Réveils habituels
</h2>
<Button
href="alarms/repeated/new"
color="outline-primary"
size="sm"
class="float-end {($page.params.kind === 'repeated' && $page.url.pathname.endsWith('/new'))?'active':''}"
>
<Icon name="plus-lg" />
</Button>
</div>
<div class="text-center">
{#if $alarmsRepeated.list !== null}
{#if $alarmsRepeated.list.length}
<div class="list-group" class:list-group-flush={flush}>
{#each $alarmsRepeated.list as alarm (alarm.id)}
<a
href="alarms/repeated/{alarm.id}"
class="list-group-item list-group-item-action"
class:active={$page.params.kind === "repeated" && $page.params.aid === alarm.id}
>
Les {weekdayStr(alarm.weekday)}s à {alarm.time}
</a>
{/each}
</div>
{:else}
<p class="fst-italic">Pas de réveil habituel programmé</p>
{/if}
{:else}
{#await alarmsRepeated.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{/await}
{/if}
</div>

View file

@ -0,0 +1,53 @@
<script>
import { page } from '$app/stores';
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import DateFormat from '$lib/components/DateFormat.svelte';
import { alarmsSingle } from '$lib/stores/alarmsingle';
export let flush = false;
</script>
<div class="d-flex justify-content-between align-items-center" class:mx-2={flush}>
<h2>
Réveils manuels
</h2>
<Button
href="alarms/single/new"
color="outline-primary"
size="sm"
class="float-end {($page.params.kind === 'single' && $page.url.pathname.endsWith('/new'))?'active':''}"
>
<Icon name="plus-lg" />
</Button>
</div>
<div class="text-center">
{#if $alarmsSingle.list !== null}
{#if $alarmsSingle.list.length}
<div class="list-group" class:list-group-flush={flush}>
{#each $alarmsSingle.list as alarm (alarm.id)}
<a
href="alarms/single/{alarm.id}"
class="list-group-item list-group-item-action"
class:active={$page.params.kind === "single" && $page.params.aid === alarm.id}
>
Le <DateFormat date={alarm.time} dateStyle="long" timeStyle="long" />
</a>
{/each}
</div>
{:else}
<p class="fst-italic">Pas de prochain réveil manuel programmé</p>
{/if}
{:else}
{#await alarmsSingle.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{/await}
{/if}
</div>

View file

@ -0,0 +1,62 @@
<script>
import {
Badge,
Button,
Card,
CardBody,
CardHeader,
Col,
Container,
ListGroup,
ListGroupItem,
Row,
Icon,
} from 'sveltestrap';
import { actions_idx } from '$lib/stores/actions';
export let routine = {
name: "Classique",
steps: [],
};
</script>
<Card>
<CardHeader>
<Button
color="outline-danger"
size="sm"
class="float-end ms-1"
>
<Icon name="trash" />
</Button>
<Button
color="outline-info"
size="sm"
class="float-end ms-1"
>
<Icon name="pencil" />
</Button>
{routine.name}
</CardHeader>
{#if routine.steps}
<ListGroup>
{#each routine.steps as step}
<ListGroupItem action>
{#if $actions_idx && $actions_idx[step.action]}
{$actions_idx[step.action].name}
{:else}
{step.action}
{/if}
<Badge class="float-end">
{step.delay/60} min
</Badge>
</ListGroupItem>
{/each}
</ListGroup>
{:else}
<CardBody>
Aucune action définie.
</CardBody>
{/if}
</Card>

View file

@ -0,0 +1,27 @@
<script>
import {
Card,
CardHeader,
ListGroup,
ListGroupItem,
Icon,
} from 'sveltestrap';
export let awakingList = [
{
id: 1,
date: new Date("2022-10-01T09:15:00.000Z"),
},
];
</script>
<Card>
<CardHeader>
Liste des réveils
</CardHeader>
<ListGroup>
{#each awakingList as awaking (awaking.id)}
<ListGroupItem>{awaking.date}</ListGroupItem>
{/each}
</ListGroup>
</Card>

View file

@ -0,0 +1,34 @@
<script>
import {
Badge,
Card,
CardHeader,
ListGroup,
ListGroupItem,
Icon,
} from 'sveltestrap';
export let routinesStats = [
{
id: 1,
name: "Classique",
nb: 10,
},
];
</script>
<Card>
<CardHeader>
Routines favorites
</CardHeader>
<ListGroup numbered>
{#each routinesStats as routine (routine.id)}
<ListGroupItem>
{routine.name}
<Badge color="primary" class="float-end">
{routine.nb}
</Badge>
</ListGroupItem>
{/each}
</ListGroup>
</Card>

View file

@ -0,0 +1,19 @@
<script>
import {
Card,
CardHeader,
CardBody,
Icon,
} from 'sveltestrap';
</script>
<Card>
<CardHeader>
Temps moyen de éteindre le réveil
</CardHeader>
<CardBody>
<p class="card-text">
10 minutes
</p>
</CardBody>
</Card>

View file

@ -0,0 +1,35 @@
<script>
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
export let begins = null;
export let ends;
const dispatch = createEventDispatcher();
let interval;
onMount(() => {
if (!begins) {
interval = setInterval(() => {
begins = new Date();
if (begins > ends) {
dispatch("reload")
}
}, 15000);
begins = new Date();
}
});
onDestroy(() => {
if (interval) {
clearInterval(interval);
}
});
export { className as class };
let className = 'text-muted';
</script>
{#if begins && ends}
<span class="{className}">
(dans {Math.trunc((ends.getTime()-begins.getTime())/5400000)}&nbsp;cycles + {Math.trunc(((ends.getTime()-begins.getTime())%5400000)/60000)}&nbsp;min)
</span>
{/if}

View file

@ -0,0 +1,17 @@
<script>
export let date;
export let dateStyle;
export let timeStyle;
function formatDate(input, dateStyle, timeStyle) {
if (typeof input === 'string') {
input = new Date(input);
}
return new Intl.DateTimeFormat(undefined, {
dateStyle,
timeStyle,
}).format(input);
}
</script>
{formatDate(date, dateStyle, timeStyle)}

View file

@ -0,0 +1,18 @@
<script>
export let startDate;
export let endDate;
export let dateStyle;
export let timeStyle;
function formatRange(startDate, endDate, dateStyle, timeStyle) {
if (typeof input === 'string') {
input = new Date(input);
}
return new Intl.DateTimeFormat(undefined, {
dateStyle,
timeStyle,
}).formatRange(startDate, endDate);
}
</script>
{formatRange(startDate, endDate, dateStyle, timeStyle)}

View file

@ -0,0 +1,31 @@
<script>
import dayjs from 'dayjs';
import {
Input,
} from 'sveltestrap';
export let format = 'YYYY-MM-DD HH:mm';
export let date = new Date();
let className = '';
export { className as class };
export let id = null;
export let required = false;
let internal;
const input = (x) => (internal = dayjs(x).format(format));
const output = (x) => {
const d = dayjs(x, format).toDate();
if (d) {
date = d.toISOString();
}
};
$: input(date)
$: output(internal)
</script>
<Input type="datetime-local" class={className} id={id} {required} bind:value={internal} />

View file

@ -0,0 +1,96 @@
<script>
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import { gongs } from '$lib/stores/gongs';
function chooseGong(gong) {
gong.setDefault().then(() => {
gongs.refresh();
});
}
export let flush = false;
export let edit = false;
export { className as class };
let className = '';
let refreshInProgress = false;
function refresh_gongs() {
refreshInProgress = true;
gongs.refresh().then(() => {
refreshInProgress = false;
});
}
</script>
<div class="d-flex justify-content-between align-items-center" class:px-2={flush}>
<h2>
Gongs
</h2>
<div>
{#if !edit}
<Button
href="musiks/gongs"
color="outline-info"
size="sm"
>
<Icon name="pencil" />
</Button>
{/if}
<Button
href="musiks/gongs/new"
color="outline-primary"
size="sm"
>
<Icon name="plus-lg" />
</Button>
<Button
color="outline-dark"
size="sm"
title="Rafraîchir la liste des gongs"
on:click={refresh_gongs}
disabled={refreshInProgress}
>
{#if !refreshInProgress}
<Icon name="arrow-clockwise" />
{:else}
<Spinner color="dark" size="sm" />
{/if}
</Button>
</div>
</div>
<div class="list-group {className}" class:list-group-flush={flush}>
{#if $gongs.list}
{#each $gongs.list as gong (gong.id)}
<button
type="button"
class="list-group-item list-group-item-action"
class:active={(edit && $page.url.pathname.indexOf('/gongs/') !== -1 && $page.params.gid == gong.id) || (!edit && gong.enabled)}
aria-current="true"
on:click={() => {
if (edit) {
goto('musiks/gongs/' + gong.id);
} else {
chooseGong(gong);
}
}}
>
{gong.name}
</button>
{/each}
{:else}
{#await gongs.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{/await}
{/if}
</div>

View file

@ -0,0 +1,99 @@
<script>
import { page } from '$app/stores'
import {
Icon,
Navbar,
NavbarBrand,
Nav,
NavItem,
NavLink,
} from 'sveltestrap';
const version = fetch('api/version', {headers: {'Accept': 'application/json'}}).then((res) => res.json())
export let activemenu = "";
$: {
const path = $page.url.pathname.split("/");
if (path.length > 1) {
activemenu = path[1];
}
}
export { className as class };
let className = '';
</script>
<Navbar container={false} class="{className} px-md-2" color="primary" dark expand="xs" style="overflow-x: auto">
<NavbarBrand href="." class="d-none d-md-block" style="padding: 0; margin: -.5rem 0;">
Réveil
</NavbarBrand>
<Nav navbar>
<NavItem class="d-block d-md-none">
<NavLink
active={activemenu === ''}
class="text-center"
href="."
>
<Icon name="house-fill" /><br class="d-inline d-md-none">
Accueil
</NavLink>
</NavItem>
<NavItem>
<NavLink
active={activemenu === 'alarms'}
class="text-center"
href="alarms"
>
<Icon name="alarm-fill" /><br class="d-inline d-md-none">
Réveils
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="musiks"
class="text-center"
active={activemenu === 'musiks'}
>
<Icon name="music-note-list" /><br class="d-inline d-md-none">
Musiques
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="routines"
class="text-center"
active={activemenu === 'routines'}
>
<Icon name="activity" /><br class="d-inline d-md-none">
Routines
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="history"
class="text-center"
active={activemenu === 'history'}
>
<Icon name="clipboard-pulse" /><br class="d-inline d-md-none">
Historique
</NavLink>
</NavItem>
<NavItem>
<NavLink
href="settings"
class="text-center"
active={activemenu === 'settings'}
>
<Icon name="gear-fill" /><br class="d-inline d-md-none">
Paramètres
</NavLink>
</NavItem>
</Nav>
<Nav class="ms-auto text-light" navbar>
<NavItem>
{#await version then v}
{v.version}
{/await}
</NavItem>
</Nav>
</Navbar>

View file

@ -0,0 +1,32 @@
<script>
let musiks = [
{
id: 1,
title: "Hall Of Fame",
artist: "The Script",
enabled: true,
},
{
id: 2,
title: "Poker face",
artist: "Lady Gaga",
},
{
id: 3,
title: "Puisque tu m'aimes encore",
artist: "Céline Dion",
enabled: true,
},
];
let tracks = [2,0,1];
</script>
<h2>
Dernières musiques jouées
</h2>
<ol class="list-group list-group-numbered">
{#each tracks as track}
<li class="list-group-item">{musiks[track].artist} &ndash; {musiks[track].title}</li>
{/each}
</ol>

View file

@ -0,0 +1,22 @@
<script>
import {
Toast,
ToastBody,
ToastHeader,
} from 'sveltestrap';
import { ToastsStore } from '$lib/stores/toasts';
</script>
<div class="toast-container position-absolute top-0 end-0 p-3">
{#each $ToastsStore.toasts as toast}
<Toast>
<ToastHeader toggle={toast.close} icon={toast.color}>
{#if toast.title}{toast.title}{:else}Gustus{/if}
</ToastHeader>
<ToastBody>
{toast.msg}
</ToastBody>
</Toast>
{/each}
</div>

View file

@ -0,0 +1,95 @@
<script>
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import {
Button,
Icon,
Spinner,
} from 'sveltestrap';
import { tracks } from '$lib/stores/tracks';
export let flush = false;
export let edit = false;
export { className as class };
let className = '';
let refreshInProgress = false;
function refresh_tracks() {
refreshInProgress = true;
tracks.refresh().then(() => {
refreshInProgress = false;
});
}
</script>
<div class="d-flex justify-content-between align-items-center" class:px-2={flush}>
<h2>
Musiques {#if !flush}du réveil{/if}
</h2>
<div>
{#if !edit}
<Button
href="musiks/tracks"
color="outline-info"
size="sm"
>
<Icon name="pencil" />
</Button>
{/if}
<Button
href="musiks/tracks/new"
color="outline-primary"
size="sm"
>
<Icon name="plus-lg" />
</Button>
<Button
color="outline-dark"
size="sm"
title="Rafraîchir la liste des pistes"
on:click={refresh_tracks}
disabled={refreshInProgress}
>
{#if !refreshInProgress}
<Icon name="arrow-clockwise" />
{:else}
<Spinner color="dark" size="sm" />
{/if}
</Button>
</div>
</div>
<div class="list-group {className}" class:list-group-flush={flush}>
{#if $tracks.list}
{#each $tracks.list as track (track.id)}
<button
type="button"
class="list-group-item list-group-item-action"
class:active={$page.url.pathname.indexOf('/tracks/') !== -1 && $page.params.tid == track.id}
aria-current="true"
on:click={() => {
if (edit) {
goto('musiks/tracks/' + track.id);
} else {
track = track.toggleEnable()
}
}}
>
{#if !edit}
<input class="form-check-input me-1" type="checkbox" checked={track.enabled}>
{/if}
<span class:fw-bold={!edit && track.enabled}>{track.name}</span>
</button>
{/each}
{:else}
{#await tracks.refresh()}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{:then}
test
{/await}
{/if}
</div>