Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
--foreground: hsl(0 0% 0%);

--muted: hsl(220 8% 85%);
--muted-foreground: hsl(0 0% 0%);
--muted-foreground: hsl(0 0% 40%);

--popover: hsl(0 0% 100%);
--popover-foreground: hsl(0 0% 0%);
Expand Down Expand Up @@ -69,16 +69,16 @@
--card: hsl(220 4% 18%);
--card-foreground: hsl(220 8% 65%);

--border: hsl(0 0% 14.9%);
--input: hsl(0 0% 14.9%);
--border: hsl(0 0% 15%);
--input: hsl(220 4% 18%);

--primary: hsl(0 0% 98%);
--primary-foreground: hsl(0 0% 9%);

--secondary: hsl(220 4% 26%);
--secondary-foreground: hsl(0 0% 98%);

--accent: hsl(0 0% 14.9%);
--accent: hsl(0 0% 15%);
--accent-foreground: hsl(0 0% 98%);
--accent-text: hsl(220 71% 77%);

Expand Down
2 changes: 1 addition & 1 deletion src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<link
rel="search"
type="application/opensearchdescription+xml"
title="MWMBL (alpha)"
title="Mwmbl (alpha)"
href="/opensearch.xml"
/>

Expand Down
2 changes: 1 addition & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const handle: Handle = async ({ event, resolve }) => {
return await resolve(event);
};

// Proxies request through SvelteKit server to MWMBL API, with authentication
// Proxies request through SvelteKit server to Mwmbl API, with authentication
// Adapted from https://sami.website/blog/sveltekit-api-reverse-proxy
const handleApiProxy: Handle = async ({ event }) => {
// build the new URL path with your API base URL, the path, and the query string
Expand Down
8 changes: 4 additions & 4 deletions src/lib/components/custom/brand/BottomLinks.svelte
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good here, but this file has conflicts. I can't resolve, because I don't have push rights to your repo. If you could re-do this commit keeping all the new changes in tact while just adding the -{new Date().getFullYear()} we could merge without extra CLI fuckery.

Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
</script>

<section class="mt-2 flex flex-col gap-1">
<div class="flex flex-row items-center text-sm font-medium text-unemphasized-2 {className}">
<div class="text-unemphasized-2 flex flex-row items-center text-sm font-medium {className}">
{#each links as link}
<Button
variant="link"
href={link.href}
class="h-fit px-0 py-0 text-sm font-medium text-unemphasized-2"
class="text-unemphasized-2 h-fit px-0 py-0 text-sm font-medium"
target="_blank"
>
{link.label}
Expand All @@ -28,7 +28,7 @@
{/if}
{/each}
</div>
<p class="flex flex-row text-sm text-unemphasized-2 {className}">
© Mwmbl 2024, under the AGPL-3.0 license
<p class="text-unemphasized-2 flex flex-row text-sm {className}">
© Mwmbl 2024-{new Date().getFullYear()}, under the AGPL-3.0 license
</p>
</section>
8 changes: 5 additions & 3 deletions src/lib/components/custom/brand/CTA.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import PhMatrixLogoBold from '~icons/ph/matrix-logo-bold';
</script>

<div
class="bg-brand-gradient bg-background/75 rounded-2xl border-2 border-black/25 p-5 bg-blend-lighten"
>
<div class="relative overflow-hidden rounded-2xl border-2 border-black/10 p-5">
<div
class="bg-brand-gradient absolute top-0 left-0 -z-10 size-full opacity-50 dark:opacity-25"
></div>

<h2 class="font-display mb-3 text-xl font-extrabold">Join the Mwmbl community</h2>
<p class="text-unemphasized-2 dark:text-white/70">
Mwmbl is powered by you — our community. We're a friendly bunch and you can find us on Matrix
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/custom/menu/MobileMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<span> Donate to keep Mwmbl running </span>
<Button
href="https://opencollective.com/mwmbl"
class="max-w-min px-6 min-[400px]:justify-self-end"
class="max-w-min min-[400px]:justify-self-end"
variant="secondary"
>
<RiMoneyDollarCircleFill class="mr-2 min-h-5 min-w-5 text-black dark:text-white" /> Donate
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/custom/menu/Options.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
});
</script>

<div class="flex flex-col gap-3">
<div class="flex flex-col gap-4">
<div class="flex w-full max-w-2xl flex-row items-center justify-start gap-3">
{#if !loaded}
<Skeleton class="bg-input h-[24px] w-[44px] rounded-full" />
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/custom/menu/SignInButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
</script>

{#if status !== 'assumeLoggedIn'}
<Button href="/account" class="max-w-min px-6">
<Button href="/account" class="max-w-min">
<RiUserLine class="mr-2 min-h-5 min-w-5 text-white dark:text-black" /> Sign In
</Button>
{:else}
<Button href="/account" class="max-w-min px-6">
<Button href="/account" class="max-w-min">
<RiUserLine class="mr-2 min-h-5 min-w-5 text-white dark:text-black" /> Account
</Button>
{/if}
108 changes: 70 additions & 38 deletions src/lib/components/custom/search/SearchBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@

import RiSearchLine from '~icons/ri/search-line';
import PhArrowSquareOutFill from '~icons/ph/arrow-square-out-fill';
import MaterialSymbolsCloseRounded from '~icons/material-symbols/close-rounded';
import RiCloseFill from '~icons/ri/close-fill';
import Spinner from '@/components/ui/spinner/spinner.svelte';

let { query }: { query?: string } = $props();

let input: HTMLInputElement | null = $state(null);
let searchBarRef: HTMLFormElement;

let searchCompletions: string[] = $state([]);
let completionsExist = $derived(
searchCompletions.length > 0 && searchCompletions[0] !== 'search: google.com '
);
let completionsVisible = $state(false);
let completionsLoading = $state(true);

// AbortControllers are used to cancel fetches when the user searchers for something
// This is to prevent the page being stuck loading completions after the user has already searched
let abortControllers: AbortController[] = [];

function fetchSearchCompletions(query: string | undefined) {
completionsLoading = searchCompletions.length === 0;
completionsVisible = !!(query && query.trim().length > 0);

if (!query || query.length === 0) {
resetCompletions();
return;
}

if (query != undefined) {
const controller = new AbortController();
const signal = controller.signal;
Expand All @@ -28,6 +38,7 @@
.then((res) => {
res.json().then((json) => {
searchCompletions = json[1];
completionsLoading = false;
});
})
.catch((e: Error) => {
Expand All @@ -38,36 +49,51 @@
});
}
}

function resetCompletions() {
completionsVisible = false;
abortControllers.forEach((controller) => controller.abort());
abortControllers = [];
searchCompletions = [];
input?.focus();
}
</script>

<svelte:window
onclick={(e) => {
// If user clicks outside of search bar, reset (hide) completions
if (!completionsVisible || !e.target || !(e.target instanceof Node)) return;
if (e.target !== searchBarRef && !searchBarRef.contains(e.target)) resetCompletions();
}}
/>

<form
class="relative flex w-full max-w-184 flex-row items-center"
action="/search"
method="get"
onsubmit={resetCompletions}
bind:this={searchBarRef}
>
<Input
type="search"
name="q"
placeholder="Search with Mwmbl..."
aria-label="Search with Mwmbl"
class={'bg-card z-20 h-12 rounded-2xl border-none p-6 text-lg ' +
(completionsExist ? ' rounded-b-none ' : '')}
class={'bg-card z-20 h-12 rounded-2xl border-none pr-12 pl-4 text-lg ' +
(completionsVisible ? ' rounded-b-none ' : '')}
autocomplete="off"
bind:ref={input}
bind:value={query}
oninput={() => fetchSearchCompletions(query)}
onclick={(e) => {
if (e.currentTarget.value.trim() !== '') fetchSearchCompletions(e.currentTarget.value);
}}
/>
{#if query == undefined || completionsExist}
{#if query == undefined || completionsVisible}
<Button
tabindex={-1}
type="submit"
class="bg-brand-gradient absolute right-3 z-30 h-8 w-8 rounded-full disabled:pointer-events-auto disabled:cursor-default disabled:opacity-100"
class="bg-brand-gradient absolute right-2 z-30 h-8 w-8 rounded-full p-0 disabled:pointer-events-auto disabled:cursor-default disabled:opacity-100"
disabled={query == undefined}
title="Search Mwmbl"
aria-label="Search Mwmbl"
Expand All @@ -80,47 +106,53 @@
query = undefined;
input?.focus();
}}
class="bg-brand-gradient absolute right-3 z-30 h-8 w-8 rounded-full"
class="bg-brand-gradient absolute right-2 z-30 h-8 w-8 rounded-full p-0"
title="Clear query and search again"
aria-label="Clear query and search again"
>
<MaterialSymbolsCloseRounded class="min-h-5 min-w-5 text-black" />
<RiCloseFill class="min-h-6 min-w-6 text-black" />
</Button>
{/if}

<Card.Root
class={'absolute top-12 z-10 flex w-[calc(100%)] rounded-t-none rounded-b-2xl border-none shadow-sm' +
(completionsExist ? ' px-4 pt-4 pb-4' : ' p-0')}
(completionsVisible ? ' min-h-16 p-3 pt-4' : ' p-0')}
>
<ol>
{#if completionsExist}
{#each searchCompletions as completion}
{#if !completion.match(/^.*: /)}
<Button variant="link" onclick={resetCompletions} href="/search?q={completion}"
>{completion}</Button
>
{:else if completion.startsWith('search: google.com ')}
<Button
target="_blank"
href="https://google.com/search?q={completion.replace(/^search: google\.com/, '')}"
>
<span>Search on Google: {completion.replace(/^search: google\.com/, '')}</span>
<RiSearchLine class="ml-1 min-h-5 min-w-5 text-black" />
</Button>
{:else if completion.startsWith('go: ')}
<Button
variant="secondary"
target="_blank"
href={'https://' + completion.replace(/^go: /, '')}
>
<span>Open website: {completion.replace(/^go: /, '')}</span>
<PhArrowSquareOutFill class="ml-1 min-h-5 min-w-5 text-black dark:text-white" />
</Button>
{/if}
{/each}
{#if completionsVisible}
{#if completionsLoading}
<div class="flex h-10 w-full items-center justify-center text-xl">
<Spinner />
</div>
{:else}
{#each searchCompletions as completion}
{#if !completion.match(/^.*: /)}
<Button variant="link" onclick={resetCompletions} href="/search?q={completion}"
>{completion}</Button
>
{:else if completion.startsWith('search: google.com ')}
<Button
target="_blank"
href="https://google.com/search?q={completion.replace(/^search: google\.com/, '')}"
>
<span>Search on Google: {completion.replace(/^search: google\.com/, '')}</span>
<RiSearchLine class="ml-1 min-h-5 min-w-5 text-black" />
</Button>
{:else if completion.startsWith('go: ')}
<Button
variant="secondary"
target="_blank"
href={'https://' + completion.replace(/^go: /, '')}
>
<span>Open website: {completion.replace(/^go: /, '')}</span>
<PhArrowSquareOutFill class="ml-1 min-h-5 min-w-5 text-black dark:text-white" />
</Button>
{/if}
{/each}
{/if}
{/if}
</ol>
{#if completionsExist}
{#if completionsVisible}
<Button
size="icon"
class="absolute right-3 bottom-3 ml-auto h-8 w-8 rounded-full"
Expand All @@ -129,7 +161,7 @@
title="Close search completions"
aria-label="Close search completions"
>
<MaterialSymbolsCloseRounded class="min-h-5 min-w-5 text-black dark:text-white" />
<RiCloseFill class="min-h-5 min-w-5 text-black dark:text-white" />
</Button>
{/if}
</Card.Root>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/ui/button/button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { type VariantProps, tv } from 'tailwind-variants';

export const buttonVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-2xl text-base font-semibold outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-5 [&_svg]:pointer-events-none [&_svg]:shrink-0",
base: "cursor-pointer focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-2xl text-base font-semibold outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-5 [&_svg]:pointer-events-none [&_svg]:shrink-0",
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/ui/input/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
bind:this={ref}
data-slot="input"
class={cn(
'selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-10 w-full min-w-0 rounded-md border bg-transparent px-3 pt-1.5 text-sm font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'selection:bg-primary dark:bg-input selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-10 w-full min-w-0 rounded-md border bg-transparent px-3 pt-1.5 text-sm font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
className
Expand All @@ -39,7 +39,7 @@
bind:this={ref}
data-slot="input"
class={cn(
'border-input bg-card selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground transition-color flex h-10 w-full min-w-0 rounded-md border px-3 py-1 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50',
'border-input bg-card selection:bg-primary dark:bg-input selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground transition-color flex h-10 w-full min-w-0 rounded-md border px-3 py-1 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50',
'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-2 focus-visible:ring-offset-2',
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
className
Expand Down
3 changes: 3 additions & 0 deletions src/lib/components/ui/spinner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Spinner from './spinner.svelte';

export { Spinner };
19 changes: 19 additions & 0 deletions src/lib/components/ui/spinner/spinner.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!-- Make it spin, and scale based on font size -->
<div class="fill-muted-foreground size-[1em] animate-spin">
<svg
width="100%"
height="100%"
viewBox="0 0 128 128"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
>
<g transform="matrix(0.765961,0,0,0.765961,-526.562,-304.06)">
<path
d="M854.563,480.521C854.563,526.636 817.123,564.076 771.008,564.076C724.893,564.076 687.453,526.636 687.453,480.521C687.453,434.406 724.893,396.966 771.008,396.966L771.008,417.855C736.421,417.855 708.342,445.934 708.342,480.521C708.342,515.107 736.421,543.187 771.008,543.187C805.594,543.187 833.674,515.107 833.674,480.521L854.563,480.521Z"
/>
</g>
</svg>
</div>
Loading