switch frontend css from bootstrap to bulma

This commit is contained in:
sam 2024-06-09 23:21:28 +02:00
parent a2f001392b
commit 50257d61f8
14 changed files with 150 additions and 71 deletions

View file

@ -1,4 +1,3 @@
using System.Diagnostics;
using Foxnouns.Backend.Database; using Foxnouns.Backend.Database;
using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Middleware;
using Foxnouns.Backend.Services; using Foxnouns.Backend.Services;

View file

@ -0,0 +1,11 @@
using NodaTime;
namespace Foxnouns.Backend.Database.Models;
public class Cache
{
public long Id { get; init; }
public required string Key { get; init; }
public required string Value { get; set; }
public Instant Expires { get; init; }
}

View file

@ -12,18 +12,20 @@
"format": "prettier --write ." "format": "prettier --write ."
}, },
"devDependencies": { "devDependencies": {
"@fontsource/firago": "^5.0.11",
"@sveltejs/adapter-node": "^5.0.1", "@sveltejs/adapter-node": "^5.0.1",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"@sveltestrap/sveltestrap": "^6.2.7", "@tabler/icons-svelte": "^3.5.0",
"@types/eslint": "^8.56.7", "@types/eslint": "^8.56.7",
"bootstrap": "^5.3.3", "bulma": "^1.0.1",
"eslint": "^9.0.0", "eslint": "^9.0.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0", "eslint-plugin-svelte": "^2.36.0",
"globals": "^15.0.0", "globals": "^15.0.0",
"prettier": "^3.1.1", "prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2", "prettier-plugin-svelte": "^3.1.2",
"sass": "^1.77.4",
"svelte": "^4.2.7", "svelte": "^4.2.7",
"svelte-check": "^3.6.0", "svelte-check": "^3.6.0",
"tslib": "^2.4.1", "tslib": "^2.4.1",

View file

@ -6,10 +6,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<script> <script>
let theme = localStorage.getItem("pronounscc-theme"); let theme = localStorage.getItem("pronounscc-theme");
if (!theme || theme === "auto") if (!theme)
theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
document.documentElement.setAttribute("data-bs-theme", theme); document.documentElement.setAttribute("data-theme", theme);
</script> </script>
%sveltekit.head% %sveltekit.head%
</head> </head>

View file

@ -0,0 +1,7 @@
@use "bulma/sass" with (
$family-primary: "FiraGO"
);
@import "@fontsource/firago/400.css";
@import "@fontsource/firago/400-italic.css";
@import "@fontsource/firago/700.css";

View file

@ -0,0 +1,10 @@
<script lang="ts">
let isOpen = false;
</script>
<div class={"navbar-item has-dropdown" + (isOpen ? " is-active" : "")}>
<button class="navbar-link" on:click={() => (isOpen = !isOpen)}><slot name="label" /></button>
<div class="navbar-dropdown">
<slot />
</div>
</div>

View file

@ -0,0 +1,10 @@
<script lang="ts">
export let divider = false;
export let href: string | undefined = undefined;
</script>
{#if divider}
<hr class="navbar-divider" />
{:else}
<a {href} class="navbar-item"><slot /></a>
{/if}

View file

@ -1,57 +1,70 @@
<script lang="ts"> <script lang="ts">
import { import { IconSun, IconMoon } from "@tabler/icons-svelte";
Navbar, import { onMount } from "svelte";
NavbarBrand, import Dropdown from "./Dropdown.svelte";
NavbarToggler, import DropdownItem from "./DropdownItem.svelte";
Collapse,
Nav,
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
NavItem,
} from "@sveltestrap/sveltestrap";
import Logo from "./Logo.svelte"; import Logo from "./Logo.svelte";
import type { User } from "$lib/api/user"; import type { User } from "$lib/api/user";
import { themeStore } from "$lib/store";
export let user: User | undefined; export let user: User | undefined;
let navIsOpen = false;
let showMenu = true; onMount(() => {
const toggleMenu = () => { let theme = localStorage.getItem("pronounscc-theme");
showMenu = !showMenu; if (!theme)
theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
themeStore.set(theme);
});
const toggleTheme = () => {
themeStore.set($themeStore === "dark" ? "light" : "dark");
document.documentElement.setAttribute("data-theme", $themeStore);
localStorage.setItem("pronounscc-theme", $themeStore);
}; };
let userMenuOpen = false;
</script> </script>
<Navbar> <nav class="navbar is-transparent" aria-label="Main navigation">
<NavbarBrand href="/" aria-label="pronouns.cc landing page"> <div class="navbar-brand">
<a href="/" class="navbar-item">
<Logo /> <Logo />
</NavbarBrand> </a>
<NavbarToggler on:click={toggleMenu} aria-label="Toggle menu" /> <button
<Collapse isOpen={showMenu} navbar expand="lg"> class={"navbar-burger" + (navIsOpen ? " is-active" : "")}
<Nav class="ms-auto" navbar> aria-label="menu"
aria-expanded="false"
on:click={() => (navIsOpen = !navIsOpen)}
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</button>
</div>
<div class={"navbar-menu" + (navIsOpen ? " is-active" : "")}>
<div class="navbar-end">
{#if user} {#if user}
<NavItem> <Dropdown>
<Dropdown nav isOpen={userMenuOpen} toggle={() => (userMenuOpen = !userMenuOpen)}> <span slot="label">@{user.username}</span>
<DropdownToggle nav caret>@{user.username}</DropdownToggle>
<DropdownMenu>
<DropdownItem href="/@{user.username}">View profile</DropdownItem> <DropdownItem href="/@{user.username}">View profile</DropdownItem>
<DropdownItem href="/settings">Settings</DropdownItem> <DropdownItem href="/settings">Settings</DropdownItem>
<DropdownItem divider /> <DropdownItem divider />
<DropdownItem href="/logout">Log out</DropdownItem> <DropdownItem href="/logout">Log out</DropdownItem>
</DropdownMenu>
</Dropdown> </Dropdown>
</NavItem>
{:else} {:else}
<NavItem> <Dropdown>
<Dropdown nav isOpen={userMenuOpen} toggle={() => (userMenuOpen = !userMenuOpen)}> <span slot="label">Not logged in</span>
<DropdownToggle nav caret>Not logged in</DropdownToggle>
<DropdownMenu>
<DropdownItem href="/login">Log in</DropdownItem> <DropdownItem href="/login">Log in</DropdownItem>
</DropdownMenu> <DropdownItem href="/register">Sign up</DropdownItem>
</Dropdown> </Dropdown>
</NavItem>
{/if} {/if}
</Nav> <button class="navbar-item" on:click={() => toggleTheme()}>
</Collapse> {#if $themeStore === "dark"}
</Navbar> <IconSun size={20} />&nbsp;Light theme
{:else}
<IconMoon size={20} />&nbsp;Dark theme
{/if}
</button>
</div>
</div>
</nav>

View file

@ -0,0 +1,9 @@
import { writable } from "svelte/store";
import { browser } from "$app/environment";
const defaultThemeValue = "light";
const initialThemeValue = browser
? window.localStorage.getItem("pronouns-theme") ?? defaultThemeValue
: defaultThemeValue;
export const themeStore = writable<string>(initialThemeValue);

View file

@ -1,11 +1,10 @@
<script lang="ts"> <script lang="ts">
import Navbar from "$lib/nav/Navbar.svelte";
import "bootstrap/dist/css/bootstrap.min.css";
import type { LayoutData } from "./$types"; import type { LayoutData } from "./$types";
import "../app.scss";
import Navbar from "$lib/nav/Navbar.svelte";
export let data: LayoutData; export let data: LayoutData;
</script> </script>
<Navbar user={data.user} /> <Navbar user={data.user} />
<slot /> <slot />

View file

@ -15,5 +15,5 @@
</p> </p>
<p> <p>
stats: {data.meta.users.total} users, {data.meta.members} members <strong>stats:</strong> {data.meta.users.total} users, {data.meta.members} members
</p> </p>

View file

@ -171,6 +171,11 @@
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.3.tgz#e65ae80ee2927b4fd8c5c26b15ecacc2b2a6cc2a" resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.3.tgz#e65ae80ee2927b4fd8c5c26b15ecacc2b2a6cc2a"
integrity sha512-HAbhAYKfsAC2EkTqve00ibWIZlaU74Z1EHwAjYr4PXF0YU2VEA1zSIKSSpKszRLRWwHzzRZXvK632u+uXzvsvw== integrity sha512-HAbhAYKfsAC2EkTqve00ibWIZlaU74Z1EHwAjYr4PXF0YU2VEA1zSIKSSpKszRLRWwHzzRZXvK632u+uXzvsvw==
"@fontsource/firago@^5.0.11":
version "5.0.11"
resolved "https://registry.yarnpkg.com/@fontsource/firago/-/firago-5.0.11.tgz#8fe3c8b47cc1d8148bc50c80189ed3aac8555cb7"
integrity sha512-XfFsLxSFMTbJTN+94yFTJyuFGmoxtykt+6rL0fj9unCeXslllirpH6KetIlbZO73NzTUmKYRvtOJdOgVbBGtaQ==
"@humanwhocodes/module-importer@^1.0.1": "@humanwhocodes/module-importer@^1.0.1":
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
@ -239,11 +244,6 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817"
integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ== integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==
"@popperjs/core@^2.11.8":
version "2.11.8"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
"@rollup/plugin-commonjs@^25.0.7": "@rollup/plugin-commonjs@^25.0.7":
version "25.0.8" version "25.0.8"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.8.tgz#c77e608ab112a666b7f2a6bea625c73224f7dd34" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.8.tgz#c77e608ab112a666b7f2a6bea625c73224f7dd34"
@ -412,12 +412,17 @@
svelte-hmr "^0.16.0" svelte-hmr "^0.16.0"
vitefu "^0.2.5" vitefu "^0.2.5"
"@sveltestrap/sveltestrap@^6.2.7": "@tabler/icons-svelte@^3.5.0":
version "6.2.7" version "3.5.0"
resolved "https://registry.yarnpkg.com/@sveltestrap/sveltestrap/-/sveltestrap-6.2.7.tgz#5b2736cbee2db973f02b09d2e9d5bf819418f1f9" resolved "https://registry.yarnpkg.com/@tabler/icons-svelte/-/icons-svelte-3.5.0.tgz#02efede4ce0ed680e0835878c6c02cd63daf9d9a"
integrity sha512-WwLLfAFUb42BGuRrf3Vbct30bQMzlEMMipN/MfxhjuLTmLQeW9muVJfPyvjtWS+mY+RjkSCoHvAp/ZobP1NLlQ== integrity sha512-mc5ardGEM7cnUA4/q6Mz5bmW9B6t28vAAOf4Wl6+KXiTwG00EjImfnIr3pS3Ihi9sFIiXvJPYRl4H5IHlgvJvQ==
dependencies: dependencies:
"@popperjs/core" "^2.11.8" "@tabler/icons" "3.5.0"
"@tabler/icons@3.5.0":
version "3.5.0"
resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.5.0.tgz#29d0dbf100c8cb392dd64f1fe8efdcfcd1f57e44"
integrity sha512-I53dC3ZSHQ2MZFGvDYJelfXm91L2bTTixS4w5jTAulLhHbCZso5Bih4Rk/NYZxlngLQMKHvEYwZQ+6w/WluKiA==
"@types/cookie@^0.6.0": "@types/cookie@^0.6.0":
version "0.6.0" version "0.6.0"
@ -607,11 +612,6 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
bootstrap@^5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.3.tgz#de35e1a765c897ac940021900fcbb831602bac38"
integrity sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -644,6 +644,11 @@ builtin-modules@^3.3.0:
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
bulma@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-1.0.1.tgz#e37261d6f8e1a3494c9378803d9958effb2715ce"
integrity sha512-+xv/BIAEQakHkR0QVz+s+RjNqfC53Mx9ZYexyaFNFo9wx5i76HXArNdwW7bccyJxa5mgV/T5DcVGqsAB19nBJQ==
callsites@^3.0.0: callsites@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -657,7 +662,7 @@ chalk@^4.0.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
chokidar@^3.4.1: "chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1:
version "3.6.0" version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
@ -1144,6 +1149,11 @@ ignore@^5.2.0, ignore@^5.3.1:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
immutable@^4.0.0:
version "4.3.6"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.6.tgz#6a05f7858213238e587fb83586ffa3b4b27f0447"
integrity sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==
import-fresh@^3.2.1: import-fresh@^3.2.1:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@ -1630,6 +1640,15 @@ sander@^0.5.0:
mkdirp "^0.5.1" mkdirp "^0.5.1"
rimraf "^2.5.2" rimraf "^2.5.2"
sass@^1.77.4:
version "1.77.4"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.4.tgz#92059c7bfc56b827c56eb116778d157ec017a5cd"
integrity sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
semver@^7.5.4, semver@^7.6.0: semver@^7.5.4, semver@^7.6.0:
version "7.6.2" version "7.6.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
@ -1676,7 +1695,7 @@ sorcery@^0.11.0:
minimist "^1.2.0" minimist "^1.2.0"
sander "^0.5.0" sander "^0.5.0"
source-map-js@^1.0.1, source-map-js@^1.2.0: "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==