chore: update to svelte 5

This commit is contained in:
Damillora 2025-02-05 17:52:14 +00:00
parent b59c52d288
commit f9fd7d152e
22 changed files with 745 additions and 744 deletions

1193
web/app/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,19 +12,19 @@
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-static": "^3.0.0", "@sveltejs/adapter-static": "^3.0.0",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.5.27",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.0",
"@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",
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-plugin-svelte": "^2.30.0", "eslint-plugin-svelte": "^2.45.1",
"sass": "^1.64.2", "sass": "^1.64.2",
"svelte": "^4.0.5", "svelte": "^5.0.0",
"svelte-check": "^3.4.3", "svelte-check": "^4.0.0",
"svelte-tags-input": "^5.0.0", "svelte-tags-input": "^6.0.2",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^5.0.0", "typescript": "^5.5.0",
"vite": "^5.0.0" "vite": "^5.4.4"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {

View File

@ -1,13 +1,18 @@
<script> <script lang="ts">
import { token } from "$lib/stores"; import { token } from "$lib/stores";
import { isTokenExpired } from "$lib/login-check"; import { isTokenExpired } from "$lib/login-check";
interface Props {
children?: import('svelte').Snippet;
}
let loggedIn = false; let { children }: Props = $props();
let loggedIn = $state(false);
token.subscribe((value) => { token.subscribe((value) => {
loggedIn = !isTokenExpired(value); loggedIn = !isTokenExpired(value);
}); });
</script> </script>
{#if loggedIn == true} {#if loggedIn == true}
<slot /> {@render children?.()}
{/if} {/if}

View File

@ -1,20 +1,25 @@
<script> <script lang="ts">
import Tags from "svelte-tags-input"; import Tags from "svelte-tags-input";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { getPost, postUpdate, getTagAutocomplete } from "$lib/api"; import { getPost, postUpdate, getTagAutocomplete } from "$lib/api";
export let isActive = false; interface Props {
export let post; isActive?: boolean;
export let onSubmit; post: any;
onSubmit: any;
}
const toggleEditModal = () => { let { isActive = $bindable(false), post, onSubmit }: Props = $props();
const toggleEditModal = (e) => {
e.preventDefault();
isActive = !isActive; isActive = !isActive;
}; };
let form = { let form = $state({
source_url: "", source_url: "",
tags: [], tags: [],
}; });
const getData = async () => { const getData = async () => {
form.source_url = post.source_url; form.source_url = post.source_url;
@ -30,7 +35,8 @@
return list; return list;
}; };
const onFormSubmit = async () => { const onFormSubmit = async (e) => {
e.preventDefault();
const response = await postUpdate(post.id, form); const response = await postUpdate(post.id, form);
toggleEditModal(); toggleEditModal();
@ -42,7 +48,7 @@
}); });
</script> </script>
<form on:submit|preventDefault={onFormSubmit}> <form onsubmit={onFormSubmit}>
<div class="panel is-warning"> <div class="panel is-warning">
<p class="panel-heading">Edit Post</p> <p class="panel-heading">Edit Post</p>
<div class="panel-block column"> <div class="panel-block column">
@ -105,7 +111,7 @@
</div> </div>
<div class="panel-block column"> <div class="panel-block column">
<button class="button is-primary" type="submit">Save</button> <button class="button is-primary" type="submit">Save</button>
<button class="button" on:click|preventDefault={toggleEditModal} <button class="button" onclick={toggleEditModal}
>Cancel</button >Cancel</button
> >
</div> </div>

View File

@ -2,9 +2,9 @@
import { token } from "$lib/stores"; import { token } from "$lib/stores";
import { isTokenExpired } from "$lib/login-check"; import { isTokenExpired } from "$lib/login-check";
let menu_shown = false; let menu_shown = $state(false);
let loggedIn = false; let loggedIn = $state(false);
token.subscribe((value) => { token.subscribe((value) => {
loggedIn = !isTokenExpired(value); loggedIn = !isTokenExpired(value);
}); });
@ -20,15 +20,15 @@
<a <a
href={"#"} href={"#"}
on:click={toggleMenu} onclick={toggleMenu}
role="button" role="button"
class="navbar-burger" class="navbar-burger"
aria-label="menu" aria-label="menu"
aria-expanded="false" aria-expanded="false"
> >
<span aria-hidden="true" /> <span aria-hidden="true"></span>
<span aria-hidden="true" /> <span aria-hidden="true"></span>
<span aria-hidden="true" /> <span aria-hidden="true"></span>
</a> </a>
</div> </div>

View File

@ -1,7 +1,7 @@
<script> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
export let posts = []; let { posts = [] } = $props();
</script> </script>
<div class="columns is-multiline"> <div class="columns is-multiline">

View File

@ -1,18 +1,20 @@
<script> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { getTagTypes, updateTag } from "$lib/api"; import { getTagTypes, updateTag } from "$lib/api";
export let tag; let {
export let data; tag,
export let toggleRenameMenu; data,
export let onSubmit; toggleRenameMenu,
onSubmit
} = $props();
let tagTypes = []; let tagTypes = $state([]);
let form = { let form = $state({
name: "", name: "",
tagTypeId: 1, tagTypeId: 1,
}; });
const getData = async () => { const getData = async () => {
tagTypes = await getTagTypes(); tagTypes = await getTagTypes();
@ -21,12 +23,12 @@
form.tagTypeId = tagType[0].id; form.tagTypeId = tagType[0].id;
}; };
const onFormSubmit = async () => { const onFormSubmit = async (e) => {
e.preventDefault();
await updateTag(tag, form); await updateTag(tag, form);
goto("/tags/" + form.name); goto("/tags/" + form.name);
toggleRenameMenu();
onSubmit(form.name); onSubmit(form.name);
}; };
@ -35,7 +37,7 @@
}); });
</script> </script>
<form on:submit|preventDefault={onFormSubmit}> <form onsubmit={onFormSubmit}>
<div class="panel is-warning"> <div class="panel is-warning">
<p class="panel-heading">Edit Tag</p> <p class="panel-heading">Edit Tag</p>
<div class="panel-block column"> <div class="panel-block column">
@ -85,7 +87,7 @@
</div> </div>
<div class="panel-block column"> <div class="panel-block column">
<button class="button is-primary" type="submit">Submit</button> <button class="button is-primary" type="submit">Submit</button>
<button on:click|preventDefault={toggleRenameMenu} class="button" <button onclick={toggleRenameMenu} class="button"
>Cancel</button >Cancel</button
> >
</div> </div>

View File

@ -1,14 +1,12 @@
<script> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { getRelatedTags } from "$lib/api"; import { getRelatedTags } from "$lib/api";
import AuthCheck from "$lib/components/AuthCheck.svelte"; import AuthCheck from "$lib/components/AuthCheck.svelte";
import TagLinkNumbered from "$lib/components/TagLinkNumbered.svelte"; import TagLinkNumbered from "$lib/components/TagLinkNumbered.svelte";
export let tag; let { tag, data, toggleRenameMenu } = $props();
export let data; let related_tags = $state([]);
export let toggleRenameMenu;
let related_tags = [];
const getData = async () => { const getData = async () => {
related_tags = await getRelatedTags({ tag }); related_tags = await getRelatedTags({ tag });
related_tags = related_tags related_tags = related_tags
@ -65,7 +63,7 @@
<AuthCheck> <AuthCheck>
<div class="panel-block column"> <div class="panel-block column">
<button <button
on:click|preventDefault={toggleRenameMenu} onclick={toggleRenameMenu}
class="button is-primary">Rename</button class="button is-primary">Rename</button
> >
</div> </div>

View File

@ -1,6 +1,5 @@
<script> <script lang="ts">
export let tag; let { tag, num } = $props();
export let num;
let tagType = tag.split(":")[0] ?? ""; let tagType = tag.split(":")[0] ?? "";
let tagName = tag.split(":")[1] ?? ""; let tagName = tag.split(":")[1] ?? "";

View File

@ -1,21 +1,24 @@
<script> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { updateTagNotes } from "$lib/api"; import { updateTagNotes } from "$lib/api";
export let tag; let {
export let data; tag,
export let toggleEditMenu; data,
export let onSubmit; toggleEditMenu,
onSubmit
} = $props();
let form = { let form = $state({
note: "", note: "",
}; });
const getData = async () => { const getData = async () => {
form.note = data.tagNote; form.note = data.tagNote;
}; };
const onFormSubmit = async () => { const onFormSubmit = async (e) => {
e.preventDefault();
await updateTagNotes(tag, form); await updateTagNotes(tag, form);
toggleEditMenu(); toggleEditMenu();
@ -27,19 +30,19 @@
}); });
</script> </script>
<form on:submit|preventDefault={onFormSubmit}> <form onsubmit={onFormSubmit}>
<div class="panel is-warning"> <div class="panel is-warning">
<p class="panel-heading">Edit Notes</p> <p class="panel-heading">Edit Notes</p>
<div class="panel-block column"> <div class="panel-block column">
<textarea <textarea
bind:value={form.note} bind:value={form.note}
class="textarea has-fixed-size" class="textarea has-fixed-size"
/> ></textarea>
<div class="content" /> <div class="content"></div>
</div> </div>
<div class="panel-block column"> <div class="panel-block column">
<button type="submit" class="button is-primary">Save</button> <button type="submit" class="button is-primary">Save</button>
<button on:click|preventDefault={toggleEditMenu} class="button" <button onclick={toggleEditMenu} class="button"
>Cancel</button >Cancel</button
> >
</div> </div>

View File

@ -1,8 +1,7 @@
<script> <script lang="ts">
import AuthCheck from "$lib/components/AuthCheck.svelte"; import AuthCheck from "$lib/components/AuthCheck.svelte";
export let data; let { data, toggleEditMenu } = $props();
export let toggleEditMenu;
</script> </script>
<div class="panel is-info"> <div class="panel is-info">
@ -15,7 +14,7 @@
<AuthCheck> <AuthCheck>
<div class="panel-block column"> <div class="panel-block column">
<button <button
on:click|preventDefault={toggleEditMenu} onclick={toggleEditMenu}
class="button is-primary">Edit</button class="button is-primary">Edit</button
> >
</div> </div>

View File

@ -1,9 +1,7 @@
<script> <script lang="ts">
import AuthCheck from "./AuthCheck.svelte"; import AuthCheck from "./AuthCheck.svelte";
import TagLinkNumbered from "./TagLinkNumbered.svelte"; import TagLinkNumbered from "./TagLinkNumbered.svelte";
export let post; let { post, toggleEditMenu, toggleDeleteMenu } = $props();
export let toggleEditMenu;
export let toggleDeleteMenu;
const trimUrl = (str) => { const trimUrl = (str) => {
if (str.length > 30) { if (str.length > 30) {
@ -70,11 +68,11 @@
<AuthCheck> <AuthCheck>
<p class="panel-block column"> <p class="panel-block column">
<button <button
on:click|preventDefault={toggleEditMenu} onclick={toggleEditMenu}
class="button is-primary">Edit</button class="button is-primary">Edit</button
> >
<button <button
on:click|preventDefault={toggleDeleteMenu} onclick={toggleDeleteMenu}
class="button is-danger">Delete</button class="button is-danger">Delete</button
> >
</p> </p>

View File

@ -1,6 +1,11 @@
<script> <script lang="ts">
import "../app.scss"; import "../app.scss";
import Navbar from "$lib/components/Navbar.svelte"; import Navbar from "$lib/components/Navbar.svelte";
interface Props {
children?: import('svelte').Snippet;
}
let { children }: Props = $props();
export const ssr = false; export const ssr = false;
</script> </script>
@ -11,4 +16,4 @@
<Navbar /> <Navbar />
<slot /> {@render children?.()}

View File

@ -4,7 +4,7 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
let searchTerms: string[] = []; let searchTerms: string[] = $state([]);
const onTagChange = (value) => { const onTagChange = (value) => {
searchTerms = value.detail.tags; searchTerms = value.detail.tags;
@ -15,7 +15,8 @@
return list; return list;
}; };
const onSearch = (i) => { const onSearch = (e) => {
e.preventDefault();
if (searchTerms.length > 0) { if (searchTerms.length > 0) {
goto(`/posts?tags=${searchTerms.join("+")}`); goto(`/posts?tags=${searchTerms.join("+")}`);
} else { } else {
@ -33,7 +34,7 @@
</div> </div>
<div class="hero-foot"> <div class="hero-foot">
<div class="container has-text-centered"> <div class="container has-text-centered">
<form on:submit|preventDefault={onSearch}> <form onsubmit={onSearch}>
<div class="field has-addons"> <div class="field has-addons">
<div class="control has-text-left is-expanded"> <div class="control has-text-left is-expanded">
<div class="control" id="tags"> <div class="control" id="tags">

View File

@ -2,11 +2,12 @@
import { login } from "$lib/api"; import { login } from "$lib/api";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
let username = ""; let username = $state("");
let password = ""; let password = $state("");
let error = ""; let error = $state("");
const doLogin = async () => { const doLogin = async (e) => {
e.preventDefault();
error = ""; error = "";
try { try {
const tokenData = await login({ username, password }); const tokenData = await login({ username, password });
@ -26,7 +27,7 @@
<section class="section"> <section class="section">
<div class="container"> <div class="container">
<form on:submit|preventDefault={doLogin}> <form onsubmit={doLogin}>
<div class="field"> <div class="field">
<label for="username" class="label">Username</label> <label for="username" class="label">Username</label>
<div class="control"> <div class="control">

View File

@ -2,12 +2,13 @@
import { register } from "$lib/api"; import { register } from "$lib/api";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
let username = ""; let username = $state("");
let password = ""; let password = $state("");
let email = ""; let email = $state("");
let error = ""; let error = "";
const doRegister = async () => { const doRegister = async (e) => {
e.preventDefault();
try { try {
const tokenData = await register({ email, username, password }); const tokenData = await register({ email, username, password });
goto("/"); goto("/");
@ -24,7 +25,7 @@
</section> </section>
<div class="container"> <div class="container">
<form on:submit|preventDefault={doRegister}> <form onsubmit={doRegister}>
<div class="field"> <div class="field">
<label for="email" class="label">Email</label> <label for="email" class="label">Email</label>
<div class="control"> <div class="control">

View File

@ -1,4 +1,6 @@
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { onMount } from "svelte"; import { onMount } from "svelte";
import { getPost, postDelete } from "$lib/api"; import { getPost, postDelete } from "$lib/api";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
@ -8,7 +10,7 @@
import { page } from "$app/stores"; import { page } from "$app/stores";
const { id } = $page.params; const { id } = $page.params;
let post: any; let post: any = $state();
const getData = async () => { const getData = async () => {
const data = await getPost({ id }); const data = await getPost({ id });
post = data; post = data;
@ -25,31 +27,34 @@
getData(); getData();
}); });
let deleteMenuShown = false; let deleteMenuShown = $state(false);
const deletePost = async () => { const deletePost = async (e) => {
e.preventDefault();
toggleDeleteMenu(); toggleDeleteMenu();
const success = await postDelete({ id }); const success = await postDelete({ id });
if (success) { if (success) {
goto("/posts"); goto("/posts");
} }
}; };
const toggleDeleteMenu = () => { const toggleDeleteMenu = (e) => {
e.preventDefault();
deleteMenuShown = !deleteMenuShown; deleteMenuShown = !deleteMenuShown;
}; };
let editMenuShown = false; let editMenuShown = $state(false);
const toggleEditMenu = () => { const toggleEditMenu = (e) => {
e.preventDefault();
editMenuShown = !editMenuShown; editMenuShown = !editMenuShown;
}; };
let imagePercentage = "0%"; let imagePercentage = $state("0%");
$: { run(() => {
if (post) if (post)
imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%"; imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%";
} });
</script> </script>
{#if post} {#if post}
@ -77,12 +82,12 @@
</div> </div>
<div class="panel-block column"> <div class="panel-block column">
<button <button
on:click|preventDefault={deletePost} onclick={deletePost}
class="button is-danger">Delete</button class="button is-danger">Delete</button
> >
<button <button
class="button" class="button"
on:click|preventDefault={toggleDeleteMenu} onclick={toggleDeleteMenu}
>Cancel</button >Cancel</button
> >
</div> </div>

View File

@ -1,4 +1,6 @@
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy';
import { getPostSearchTag, getTag, getTagAutocomplete } from "$lib/api"; import { getPostSearchTag, getTag, getTagAutocomplete } from "$lib/api";
import TagLinkNumbered from "$lib/components/TagLinkNumbered.svelte"; import TagLinkNumbered from "$lib/components/TagLinkNumbered.svelte";
import PostGallery from "$lib/components/Post/PostGallery.svelte"; import PostGallery from "$lib/components/Post/PostGallery.svelte";
@ -8,17 +10,17 @@
import { beforeNavigate, goto } from "$app/navigation"; import { beforeNavigate, goto } from "$app/navigation";
import { page as currentPage } from '$app/stores'; import { page as currentPage } from '$app/stores';
$: url = $currentPage.url; let url = $derived($currentPage.url);
let searchTerms = []; let searchTerms = $state([]);
let page = 1; let page = $state(1);
let totalPages = 1; let totalPages = $state(1);
let pagination = []; let pagination = $state([]);
let posts = []; let posts = $state([]);
let postCount = 0; let postCount = 0;
let tags = []; let tags = $state([]);
let tagInfo = null; let tagInfo = $state(null);
let categorizedTags = {}; let categorizedTags = {};
const getData = async () => { const getData = async () => {
@ -47,7 +49,7 @@
tagInfo = await getTag({ tag: searchTerms[0] }); tagInfo = await getTag({ tag: searchTerms[0] });
} }
}; };
let tagQuery; let tagQuery = $state();
const onTagChange = (value) => { const onTagChange = (value) => {
searchTerms = value.detail.tags; searchTerms = value.detail.tags;
@ -58,7 +60,7 @@
return list; return list;
}; };
$: { run(() => {
tagQuery = url.searchParams.get('tags'); tagQuery = url.searchParams.get('tags');
if (tagQuery) { if (tagQuery) {
searchTerms = tagQuery.split(" "); searchTerms = tagQuery.split(" ");
@ -69,8 +71,9 @@
posts = []; posts = [];
page = 1; page = 1;
getData(); getData();
} });
const onSearch = (i) => { const onSearch = (e) => {
e.preventDefault();
if (searchTerms.length > 0) { if (searchTerms.length > 0) {
goto(`/posts?tags=${searchTerms.join("+")}`); goto(`/posts?tags=${searchTerms.join("+")}`);
} else { } else {
@ -92,7 +95,7 @@
<div class="columns is-multiline"> <div class="columns is-multiline">
<div class="column is-full"> <div class="column is-full">
<div class="block"> <div class="block">
<form on:submit|preventDefault={onSearch}> <form onsubmit={onSearch}>
<div class="field has-addons"> <div class="field has-addons">
<div class="control is-expanded"> <div class="control is-expanded">
<div class="control" id="tags"> <div class="control" id="tags">
@ -173,13 +176,13 @@
> >
<a <a
href={null} href={null}
on:click={changePage(page - 1)} onclick={changePage(page - 1)}
class="pagination-previous" class="pagination-previous"
class:is-disabled={page == 1}>Previous</a class:is-disabled={page == 1}>Previous</a
> >
<a <a
href={null} href={null}
on:click={changePage(page + 1)} onclick={changePage(page + 1)}
class="pagination-next" class="pagination-next"
class:is-disabled={page == totalPages} class:is-disabled={page == totalPages}
>Next</a >Next</a
@ -197,7 +200,7 @@
<li> <li>
<a <a
href={null} href={null}
on:click={() => onclick={() =>
changePage(pageEntry)} changePage(pageEntry)}
class="pagination-link" class="pagination-link"
class:is-current={page == class:is-current={page ==

View File

@ -1,15 +1,17 @@
<script> <script>
import { run } from 'svelte/legacy';
import { getTags } from "$lib/api"; import { getTags } from "$lib/api";
let tags = []; let tags = $state([]);
const getData = async () => { const getData = async () => {
const data = await getTags(); const data = await getTags();
tags = data; tags = data;
}; };
$: { run(() => {
getData(); getData();
} });
</script> </script>

View File

@ -10,10 +10,10 @@
import { page } from "$app/stores"; import { page } from "$app/stores";
let { tag } = $page.params; let { tag } = $state($page.params);
let data; let data = $state();
let posts = []; let posts = $state([]);
const getData = async () => { const getData = async () => {
if (tag) { if (tag) {
@ -28,12 +28,13 @@
} }
}; };
let renameMenuShown = false; let renameMenuShown = $state(false);
const toggleRenameMenu = () => { const toggleRenameMenu = (e) => {
e.preventDefault();
renameMenuShown = !renameMenuShown; renameMenuShown = !renameMenuShown;
}; };
let editMenuShown = false; let editMenuShown = $state(false);
const toggleEditMenu = () => { const toggleEditMenu = () => {
editMenuShown = !editMenuShown; editMenuShown = !editMenuShown;
}; };

View File

@ -4,16 +4,16 @@
import Tags from "svelte-tags-input"; import Tags from "svelte-tags-input";
import AuthRequired from "$lib/components/AuthRequired.svelte"; import AuthRequired from "$lib/components/AuthRequired.svelte";
let currentProgress = 0; let currentProgress = $state(0);
let fileName = ""; let fileName = $state("");
let similar = []; let similar = $state([]);
let form = { let form = $state({
blob_id: "", blob_id: "",
source_url: "", source_url: "",
tags: [], tags: [],
}; });
const onProgress = (e) => { const onProgress = (e) => {
var percentCompleted = Math.round((e.loaded * 100) / e.total); var percentCompleted = Math.round((e.loaded * 100) / e.total);
@ -43,7 +43,8 @@
return list; return list;
}; };
const onSubmit = async () => { const onSubmit = async (e) => {
e.preventDefault();
const response = await postCreate(form); const response = await postCreate(form);
goto(`/post/${response.id}`); goto(`/post/${response.id}`);
}; };
@ -54,7 +55,7 @@
<section class="section"> <section class="section">
<div class="container"> <div class="container">
<h1 class="title">Upload Image</h1> <h1 class="title">Upload Image</h1>
<form on:submit|preventDefault={onSubmit}> <form onsubmit={onSubmit}>
<div class="field"> <div class="field">
<label for="file" class="label">Image File</label> <label for="file" class="label">Image File</label>
<div class="control"> <div class="control">
@ -65,10 +66,10 @@
class="file-input" class="file-input"
type="file" type="file"
name="resume" name="resume"
on:change={onFileChange} onchange={onFileChange}
/> />
<span class="file-cta"> <span class="file-cta">
<span class="file-icon" /> <span class="file-icon"></span>
<span class="file-label"> Choose a file… </span> <span class="file-label"> Choose a file… </span>
</span> </span>
</label> </label>

View File

@ -3,7 +3,7 @@
import { getUserProfile } from "$lib/api"; import { getUserProfile } from "$lib/api";
import AuthRequired from "$lib/components/AuthRequired.svelte"; import AuthRequired from "$lib/components/AuthRequired.svelte";
let user; let user = $state();
const getData = async () => { const getData = async () => {
user = await getUserProfile(); user = await getUserProfile();