Compare commits
6 Commits
fb01fe583e
...
d0cfefaa3d
| Author | SHA1 | Date | |
|---|---|---|---|
| d0cfefaa3d | |||
| 9a0b73d27c | |||
| b5ace9871d | |||
| 981566c3ba | |||
| 3aa6590c9a | |||
| ca2bd2f50a |
42
README.md
42
README.md
@@ -1,38 +1,8 @@
|
|||||||
# sv
|
# Svelte-Kit RE Charge.re
|
||||||
|
|
||||||
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
### Missing in TODO:
|
||||||
|
|
||||||
## Creating a project
|
- [ ] Localizzazione
|
||||||
|
- [ ] Opzione per selezione lingue
|
||||||
If you're seeing this, you've probably already done this step. Congrats!
|
- [ ] Aggiornamento paraglide
|
||||||
|
- [ ] Pagina di "attesa 30 secondi avvio carica"
|
||||||
```bash
|
|
||||||
# create a new project in the current directory
|
|
||||||
npx sv create
|
|
||||||
|
|
||||||
# create a new project in my-app
|
|
||||||
npx sv create my-app
|
|
||||||
```
|
|
||||||
|
|
||||||
## Developing
|
|
||||||
|
|
||||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# or start the server and open the app in a new browser tab
|
|
||||||
npm run dev -- --open
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
To create a production version of your app:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
You can preview the production build with `npm run preview`.
|
|
||||||
|
|
||||||
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
{#if show}
|
{#if show}
|
||||||
<div class="visible fixed inset-0 h-screen w-screen z-20 pointer-events-auto flex flex-col justify-end items-center">
|
<div class="visible fixed inset-0 h-screen w-screen z-20 pointer-events-auto flex flex-col justify-end items-center">
|
||||||
<button type="button" class="bg-base-100/50 w-full grow z-20"
|
<button type="button" class="bg-base-100/50 absolute inset-0 h-full w-full"
|
||||||
transition:fade={{duration:200}}
|
transition:fade={{duration:200}}
|
||||||
onclick={closeOverlay}
|
onclick={closeOverlay}
|
||||||
aria-label="Close Overlay"
|
aria-label="Close Overlay"
|
||||||
|
|||||||
60
src/lib/ToastSystem/Toast.svelte
Normal file
60
src/lib/ToastSystem/Toast.svelte
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
melt,
|
||||||
|
type Toast,
|
||||||
|
type ToastsElements,
|
||||||
|
} from '@melt-ui/svelte';
|
||||||
|
import type { ToastData } from "$lib/ToastSystem/types";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
elements: ToastsElements,
|
||||||
|
toast: Toast<ToastData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const { elements, toast }: Props = $props();
|
||||||
|
const { content, title, description, close } = $derived(elements);
|
||||||
|
const { data, id, getPercentage } = $derived(toast);
|
||||||
|
|
||||||
|
const alertClass = $derived.by(() => {
|
||||||
|
switch (data.type) {
|
||||||
|
case "success":
|
||||||
|
return 'alert-success';
|
||||||
|
case "warning":
|
||||||
|
return 'alert-warning';
|
||||||
|
case "error":
|
||||||
|
return 'alert-error';
|
||||||
|
case "info":
|
||||||
|
return 'alert-info';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let percentage = $state(0);
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
let frame: number;
|
||||||
|
const updatePercentage = () => {
|
||||||
|
percentage = getPercentage();
|
||||||
|
frame = requestAnimationFrame(updatePercentage);
|
||||||
|
};
|
||||||
|
frame = requestAnimationFrame(updatePercentage);
|
||||||
|
return () => cancelAnimationFrame(frame);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div use:melt={$content(id)} class="relative w-[70%] visible">
|
||||||
|
<div class="absolute w-full flex flex-col px-2">
|
||||||
|
<progress class="progress h-1 w-full" value={percentage} max="100"></progress>
|
||||||
|
</div>
|
||||||
|
<div class={["alert", alertClass]}>
|
||||||
|
<button use:melt={$close(id)} aria-label="close notification" class="absolute right-2 top-0">x</button>
|
||||||
|
<h3 use:melt={$title(id)} class="font-bold">
|
||||||
|
{data.title}
|
||||||
|
</h3>
|
||||||
|
<div use:melt={$description(id)}>
|
||||||
|
{data.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
23
src/lib/ToastSystem/Toaster.svelte
Normal file
23
src/lib/ToastSystem/Toaster.svelte
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<script lang="ts" module>
|
||||||
|
import { createToaster } from '@melt-ui/svelte';
|
||||||
|
import type { ToastData } from "$lib/ToastSystem/types";
|
||||||
|
|
||||||
|
const {
|
||||||
|
elements,
|
||||||
|
helpers,
|
||||||
|
states: { toasts },
|
||||||
|
actions: { portal }
|
||||||
|
} = createToaster<ToastData>();
|
||||||
|
|
||||||
|
export const addToast = helpers.addToast;
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
import Toast from "$lib/ToastSystem/Toast.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div use:portal
|
||||||
|
class="fixed w-screen h-screen top-0 z-50 pb-4 flex flex-col-reverse justify-start items-center gap-2 invisible">
|
||||||
|
{#each $toasts as toast (toast.id)}
|
||||||
|
<Toast {elements} {toast}/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
5
src/lib/ToastSystem/types.ts
Normal file
5
src/lib/ToastSystem/types.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export type ToastData = {
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
type: 'info' | 'success' | 'warning' | 'error',
|
||||||
|
}
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<script lang="ts" module>
|
|
||||||
import { createToaster, melt } from '@melt-ui/svelte';
|
|
||||||
|
|
||||||
export type ToastData = {
|
|
||||||
title: string
|
|
||||||
description: string
|
|
||||||
color: string
|
|
||||||
}
|
|
||||||
// TODO: Change color with type e setta classe
|
|
||||||
|
|
||||||
// TODO: Usa getPercentage per mostrare la loading bar sugli alert!
|
|
||||||
|
|
||||||
const {
|
|
||||||
elements: { content, title, description, close },
|
|
||||||
helpers,
|
|
||||||
states: { toasts },
|
|
||||||
actions: { portal }
|
|
||||||
} = createToaster<ToastData>();
|
|
||||||
|
|
||||||
export const addToast = helpers.addToast;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div use:portal class="fixed w-screen top-0 z-50 m-4 flex flex-col items-center gap-2 invisible">
|
|
||||||
{#each $toasts as { id, data } (id)}
|
|
||||||
<div use:melt={$content(id)} class="alert alert-info relative w-[70%] visible">
|
|
||||||
<div>
|
|
||||||
<h3 use:melt={$title(id)} class="font-bold">
|
|
||||||
{data.title}
|
|
||||||
<!-- <span style:color={data.color}></span>-->
|
|
||||||
</h3>
|
|
||||||
<div use:melt={$description(id)}>
|
|
||||||
{data.description}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button use:melt={$close(id)} aria-label="close notification" class="absolute right-2 top-0">x</button>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
import Toaster from "$lib/Toaster.svelte";
|
import Toaster from "$lib/ToastSystem/Toaster.svelte";
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { scale } from 'svelte/transition';
|
import { scale } from 'svelte/transition';
|
||||||
import { goto } from "$app/navigation";
|
import { goto, invalidate } from "$app/navigation";
|
||||||
import BSlideOverlay from "$lib/BSlideOverlay.svelte";
|
import BSlideOverlay from "$lib/BSlideOverlay.svelte";
|
||||||
import { addToast } from '$lib/Toaster.svelte';
|
import { addToast } from '$lib/ToastSystem/Toaster.svelte';
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
|
|
||||||
@@ -13,37 +13,43 @@
|
|||||||
if (startingCharge) return;
|
if (startingCharge) return;
|
||||||
startingCharge = true;
|
startingCharge = true;
|
||||||
try {
|
try {
|
||||||
// TODO: StartCharge fetch request
|
const response = await fetch(`/api/public/1/chargecontroller/${data.qrcode}/start_charge/`, {
|
||||||
// const response = await fetch(`/api/public/1/chargecontroller/${data.qrcode}/start_charge/`, {
|
method: 'POST',
|
||||||
// method: 'POST',
|
headers: {
|
||||||
// headers: {
|
'Accept': 'application/json',
|
||||||
// 'Accept': 'application/json',
|
}
|
||||||
// }
|
});
|
||||||
// });
|
if (response.ok) {
|
||||||
console.log("nop");
|
addToast({
|
||||||
|
closeDelay: 5000,
|
||||||
|
data: {
|
||||||
|
title: 'Charge Started',
|
||||||
|
description: '',
|
||||||
|
type: 'success',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await invalidate('app:chargecontroller');
|
||||||
await goto(`/${data.qrcode}/status`);
|
await goto(`/${data.qrcode}/status`);
|
||||||
|
} else {
|
||||||
|
addToast({
|
||||||
|
closeDelay: 5000,
|
||||||
|
data: {
|
||||||
|
title: 'Error',
|
||||||
|
description: response.statusText ?? 'unknown',
|
||||||
|
type: 'error',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
startingCharge = false;
|
startingCharge = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function test() {
|
|
||||||
addToast({
|
|
||||||
closeDelay: 50000,
|
|
||||||
data: {
|
|
||||||
title: 'Success',
|
|
||||||
description: 'The resource was created!',
|
|
||||||
color: 'green'
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="grid grid-rows-6 h-full w-full">
|
<div class="grid grid-rows-6 h-full w-full">
|
||||||
<div class="row-start-5 col-start-1 flex flex-col justify-center items-center">
|
<div class="row-start-5 col-start-1 flex flex-col justify-center items-center">
|
||||||
<div class="visible">
|
<div class="visible">
|
||||||
<button class="btn btn-primary btn-lg uppercase" onclick={() => showOverlay = true}>Attivare la Ricarica</button>
|
<button class="btn btn-primary btn-lg uppercase" onclick={() => showOverlay = true}>Attivare la Ricarica</button>
|
||||||
<button class="btn btn-secondary" onclick={test}>Test</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BSlideOverlay bind:show={showOverlay} closable={!startingCharge}>
|
<BSlideOverlay bind:show={showOverlay} closable={!startingCharge}>
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { redirect } from "@sveltejs/kit";
|
|||||||
|
|
||||||
export const load: PageLoad = async ({ parent }) => {
|
export const load: PageLoad = async ({ parent }) => {
|
||||||
const parentData = await parent();
|
const parentData = await parent();
|
||||||
if (parentData.user === null) return redirect(303, `${parentData.qrcode}/login`);
|
if (parentData.user === null) return redirect(303, `/${parentData.qrcode}/login`);
|
||||||
else {
|
else {
|
||||||
if (!parentData.chargePermission.includes(parentData.qrcode)) {
|
if (!parentData.chargePermission.includes(parentData.qrcode)) {
|
||||||
return redirect(303, `${parentData.qrcode}/forbidden`);
|
return redirect(303, `/${parentData.qrcode}/forbidden`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (parentData.chargecontroller.active_charge !== null) return redirect(303, `/${parentData.qrcode}/status`);
|
||||||
return parentData;
|
return parentData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
import { onMount, type Snippet } from "svelte";
|
import { onMount, type Snippet } from "svelte";
|
||||||
import type { SvelteHTMLElements } from "svelte/elements";
|
import type { SvelteHTMLElements } from "svelte/elements";
|
||||||
|
|
||||||
|
if (import.meta.env.MODE === 'production') {
|
||||||
// Fix bundling bug for leaflet default marker icon on production
|
// Fix bundling bug for leaflet default marker icon on production
|
||||||
L.Icon.Default.prototype.options.iconUrl = lmiUrl;
|
L.Icon.Default.prototype.options.iconUrl = lmiUrl;
|
||||||
L.Icon.Default.prototype.options.iconRetinaUrl = lmi2Url;
|
L.Icon.Default.prototype.options.iconRetinaUrl = lmi2Url;
|
||||||
L.Icon.Default.prototype.options.shadowUrl = lmsUrl;
|
L.Icon.Default.prototype.options.shadowUrl = lmsUrl;
|
||||||
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
x: number,
|
x: number,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { goto, invalidate } from "$app/navigation";
|
import { goto, invalidate } from "$app/navigation";
|
||||||
import { scale } from 'svelte/transition';
|
import { scale } from 'svelte/transition';
|
||||||
|
import { addToast } from '$lib/ToastSystem/Toaster.svelte';
|
||||||
import BatteryIcon from "$lib/icons/BatteryIcon.svelte";
|
import BatteryIcon from "$lib/icons/BatteryIcon.svelte";
|
||||||
import BSlideOverlay from "$lib/BSlideOverlay.svelte";
|
import BSlideOverlay from "$lib/BSlideOverlay.svelte";
|
||||||
|
|
||||||
@@ -32,9 +33,33 @@
|
|||||||
if (stoppingCharge) return;
|
if (stoppingCharge) return;
|
||||||
stoppingCharge = true;
|
stoppingCharge = true;
|
||||||
try {
|
try {
|
||||||
// TODO: StopCharge fetch request
|
const response = await fetch(`/api/public/1/chargecontroller/${data.qrcode}/stop_charge/`, {
|
||||||
console.log("nop");
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
addToast({
|
||||||
|
closeDelay: 5000,
|
||||||
|
data: {
|
||||||
|
title: 'Charge Stopped',
|
||||||
|
description: '',
|
||||||
|
type: 'success',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await invalidate('app:chargecontroller');
|
||||||
await goto(`/${data.qrcode}`);
|
await goto(`/${data.qrcode}`);
|
||||||
|
} else {
|
||||||
|
addToast({
|
||||||
|
closeDelay: 5000,
|
||||||
|
data: {
|
||||||
|
title: 'Error',
|
||||||
|
description: response.statusText ?? 'unknown',
|
||||||
|
type: 'error',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
stoppingCharge = false;
|
stoppingCharge = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { redirect } from "@sveltejs/kit";
|
|||||||
|
|
||||||
export const load: PageLoad = async ({ parent }) => {
|
export const load: PageLoad = async ({ parent }) => {
|
||||||
const parentData = await parent();
|
const parentData = await parent();
|
||||||
if (parentData.user === null) return redirect(303, `${parentData.qrcode}/login`);
|
if (parentData.user === null) return redirect(303, `/${parentData.qrcode}/login`);
|
||||||
|
if (parentData.chargecontroller.active_charge === null) return redirect(303, `/${parentData.qrcode}`);
|
||||||
return parentData;
|
return parentData;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user