Compare commits

...

12 commits

Author SHA1 Message Date
dcd386ad86 Merge pull request 'svelte-5-migration' (#1) from svelte-5-migration into main
Reviewed-on: #1
2024-12-27 22:08:57 +01:00
a44e7c9594 Fix dynamic env references 2024-12-27 20:57:50 +00:00
0b19232800 Undo fixing attempt 2024-12-27 20:56:52 +00:00
8daffd6fc1 Remove PUBLIC_BASE_URL for now 2024-12-27 20:53:20 +00:00
a21ee63baa Fix lucide svelte 2024-12-27 20:51:23 +00:00
5445f19c37 Fix dynamic env references 2024-12-27 20:45:10 +00:00
3bdc7d3f5e Fix houdini 2024-12-27 20:41:49 +00:00
ea334128f6 Fix GQL 2024-12-27 20:39:13 +00:00
1973d1a2df Fix svelte-preprocess 2024-12-27 20:34:06 +00:00
f7b786805b Cleanup dependencies 2024-12-27 20:27:31 +00:00
570c4a6e09 Migrate to Svelte 5 2024-12-13 01:16:52 +00:00
20de6e7133 Migrate to SvelteKit 2 2024-12-13 01:06:50 +00:00
38 changed files with 3167 additions and 1587 deletions

4294
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,8 +12,8 @@
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@sveltejs/kit": "^2.5.27",
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"@types/animejs": "^3.1.7",
"@types/howler": "^2.2.7",
"@types/luxon": "^3.3.1",
@ -21,33 +21,31 @@
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"eslint-plugin-svelte": "^2.45.1",
"houdini": "^1.4.0",
"houdini-svelte": "^2.1.0",
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.2.6",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2",
"houdini": "^1.2.46",
"houdini-svelte": "^1.2.46"
"typescript": "^5.5.0",
"vite": "^5.4.4"
},
"type": "module",
"dependencies": {
"@directus/sdk": "^14.0.0",
"@fontsource-variable/roboto-flex": "^5.0.5",
"@sveltejs/adapter-cloudflare": "^2.3.1",
"@sveltejs/adapter-static": "^2.0.2",
"@sveltejs/adapter-cloudflare": "^4.8.0",
"@ts-ghost/admin-api": "^4.0.1",
"@ts-ghost/content-api": "^4.0.6",
"animejs": "^3.2.1",
"feed": "^4.2.2",
"houdini": "^1.2.46",
"houdini-preprocess": "^0.13.10",
"howler": "^2.2.3",
"lucide-svelte": "^0.260.0",
"lucide-svelte": "^0.468.0",
"luxon": "^3.4.4",
"sass": "^1.63.6",
"simple-icons": "^9.5.0"
"simple-icons": "^9.5.0",
"svelte-preprocess": "^6.0.3"
}
}

View file

@ -1,15 +1,29 @@
<script lang="ts">
import { fade } from 'svelte/transition';
export let pictureUrl: string | null = null;
export let pictureAlt: string | null = null;
export let topic: string | null = null;
export let title: string;
export let href: string;
export let excerpt: string | null = null;
export let readingTimeMinutes: number | null = null;
export let mode: 'vertical' | 'horizontal' = 'horizontal';
export let fadeOffset: number | null = null;
interface Props {
pictureUrl?: string | null;
pictureAlt?: string | null;
topic?: string | null;
title: string;
href: string;
excerpt?: string | null;
readingTimeMinutes?: number | null;
mode?: 'vertical' | 'horizontal';
fadeOffset?: number | null;
}
let {
pictureUrl = null,
pictureAlt = null,
topic = null,
title,
href,
excerpt = null,
readingTimeMinutes = null,
mode = 'horizontal',
fadeOffset = null
}: Props = $props();
</script>
<a

View file

@ -3,12 +3,40 @@
import type {AnswerFragment} from '$houdini';
import { tokenStore } from '$lib/tokenStore';
import { ArrowUp } from 'lucide-svelte';
import { createEventDispatcher } from 'svelte';
//import { createEventDispatcher } from 'svelte';
export let episode: string|undefined;
export let answer: AnswerFragment
$: answerFragment = fragment(answer, graphql(`
const setUpvote = $derived(graphql(`
mutation SetUpvote($episode: ID!, $response:ID!, $upvote:Boolean!) {
setUpvote(episode:$episode, response:$response, upvote:$upvote) {
id
upvoteCount
didUpvote
}
}
`))
const deleteMutation = $derived(graphql(`
mutation Delete($episode: ID!, $response:ID!) {
deleteResponse(episode:$episode, response:$response)
}
`))
let upvoteLoading = $state(false);
interface Props {
episode: string|undefined;
answer: AnswerFragment;
admin?: boolean;
}
let { episode, answer, admin = false }: Props = $props();
/*const dispatch = createEventDispatcher<{
"invalidate": undefined
}>()*/
let answerFragment = $derived(fragment(answer, graphql(`
fragment AnswerFragment on Answer {
id
text
@ -17,31 +45,7 @@
didUpvote
isOwnedByMe
}
`))
const setUpvote = graphql(`
mutation SetUpvote($episode: ID!, $response:ID!, $upvote:Boolean!) {
setUpvote(episode:$episode, response:$response, upvote:$upvote) {
id
upvoteCount
didUpvote
}
}
`)
const deleteMutation = graphql(`
mutation Delete($episode: ID!, $response:ID!) {
deleteResponse(episode:$episode, response:$response)
}
`)
let upvoteLoading = false;
export let admin = false;
const dispatch = createEventDispatcher<{
"invalidate": undefined
}>()
`)))
</script>
<div class="answer" class:owner={$answerFragment.isOwnedByMe}>
@ -49,7 +53,7 @@
<div class="owner-flag">Your Reponse</div>
{/if}
<div class="controls">
<button class:upvoted={$answerFragment.didUpvote} on:click={async () => {
<button class:upvoted={$answerFragment.didUpvote} onclick={async () => {
upvoteLoading = true;
try {
@ -68,13 +72,13 @@
<span class="count">{$answerFragment.upvoteCount}</span>
</button>
{#if $answerFragment.isOwnedByMe||admin}
<button on:click={async () => {
<button onclick={async () => {
await deleteMutation.mutate({
episode: episode||"",
response: $answerFragment.id
})
dispatch("invalidate", undefined)
//dispatch("invalidate", undefined)
}} class="delete">Delete</button>
{/if}
</div>

View file

@ -4,14 +4,19 @@
import { setBearer, tokenStore } from "$lib/tokenStore";
import {Key, Circle} from "lucide-svelte";
import { onMount } from "svelte";
interface Props {
children?: import('svelte').Snippet;
}
let loading = false;
let { children }: Props = $props();
const getToken = graphql(`
let loading = $state(false);
const getToken = $derived(graphql(`
mutation GetToken($password: String) {
authenticate(password: $password)
}
`)
`))
onMount(() => {
if(typeof window == "undefined") {
@ -49,7 +54,7 @@
{#if browser||loading}
{#if $tokenStore}
<slot />
{@render children?.()}
{:else}
<div class="authenticate-nag">
<div class="icon">
@ -59,7 +64,7 @@
<p>To use this function you will need to authenticate.</p>
<button on:click={loginAnonymous} disabled={loading}>Authenticate as Anonymous</button>
<button onclick={loginAnonymous} disabled={loading}>Authenticate as Anonymous</button>
</div>
{/if}
{:else}

View file

@ -22,7 +22,7 @@
<span>Currently fetching the content...</span>
</div>
{#each [0, 1, 2, 3, 4, 5, 6, 7, 8] as ignored}
<div class="load-placeholder" data-idx={ignored} />
<div class="load-placeholder" data-idx={ignored}></div>
{/each}
{:then content}
{#each content as piece}

View file

@ -2,7 +2,11 @@
import type { Content } from '$lib/contentTypes';
import { baseUrl } from '$lib/seoUtils';
export let piece: Content & { type: 'article' };
interface Props {
piece: Content & { type: 'article' };
}
let { piece }: Props = $props();
</script>
<a

View file

@ -4,7 +4,11 @@
import { baseUrl } from '$lib/seoUtils';
import { siInstagram, siYoutube } from 'simple-icons';
export let piece: Content & { type: 'media' };
interface Props {
piece: Content & { type: 'media' };
}
let { piece }: Props = $props();
</script>
<a

View file

@ -1,19 +1,25 @@
<script lang="ts">
import { run } from 'svelte/legacy';
import type { EventAttendance } from '$lib/events';
import { ExternalLink } from 'lucide-svelte';
import { DateTime } from 'luxon';
export let event: EventAttendance;
interface Props {
event: EventAttendance;
}
$: startDate = DateTime.fromISO(event.start_date);
let { event }: Props = $props();
let startDate = $derived(DateTime.fromISO(event.start_date));
//$: endDate = DateTime.fromISO(event.end_date);
$: url = event.event.url ? new URL(event.event.url) : null;
$: {
let url = $derived(event.event.url ? new URL(event.event.url) : null);
run(() => {
if (url && !url.searchParams.has('ref')) {
url.searchParams.set('ref', 'pupraider.net');
}
}
});
</script>
<div class="event">

View file

@ -1,14 +1,18 @@
<script lang="ts">
export let shimmer = true;
export let outline = false;
interface Props {
shimmer?: boolean;
outline?: boolean;
}
let { shimmer = true, outline = false }: Props = $props();
</script>
<div class="event">
<div class="calendar" class:shimmer class:outline />
<div class="calendar" class:shimmer class:outline></div>
<div class="details" class:outline>
<div class="details-main">
<span class="date-location" class:shimmer />
<span class="title" class:shimmer />
<span class="date-location" class:shimmer></span>
<span class="title" class:shimmer></span>
</div>
</div>
</div>

View file

@ -3,8 +3,12 @@
import Parameters from '$lib/parameters';
import { onMount } from 'svelte';
export let pageTitle: string;
export let url: string;
interface Props {
pageTitle: string;
url: string;
}
let { pageTitle, url }: Props = $props();
onMount(() => {
if (!browser) return;
@ -30,4 +34,4 @@
});
</script>
<div id="remark42" />
<div id="remark42"></div>

View file

@ -1,20 +1,38 @@
<script lang="ts">
/* eslint svelte/no-at-html-tags: "off" */
export let robots: 'noindex' | 'noindex,nofollow' | 'nofollow' | undefined = undefined;
export let title: string;
export let keywords = '';
export let includeDefaultKeywords = true;
export let description = '';
export let type: 'website' | 'article' | 'page' = 'website';
export let image: string | undefined = undefined;
export let canonical: string;
export let publishedTime: string | undefined = undefined;
export let modifiedTime: string | undefined = undefined;
export let section: string | undefined = undefined;
export let linkedData: object | undefined = undefined;
interface Props {
/* eslint svelte/no-at-html-tags: "off" */
robots?: 'noindex' | 'noindex,nofollow' | 'nofollow' | undefined;
title: string;
keywords?: string;
includeDefaultKeywords?: boolean;
description?: string;
type?: 'website' | 'article' | 'page';
image?: string | undefined;
canonical: string;
publishedTime?: string | undefined;
modifiedTime?: string | undefined;
section?: string | undefined;
linkedData?: object | undefined;
}
let {
robots = undefined,
title,
keywords = '',
includeDefaultKeywords = true,
description = '',
type = 'website',
image = undefined,
canonical,
publishedTime = undefined,
modifiedTime = undefined,
section = undefined,
linkedData = undefined
}: Props = $props();
let ldJson = linkedData
? '<' + 'script type="application/ld+json">' + JSON.stringify(linkedData) + '<' + '/script>'

View file

@ -1,5 +1,9 @@
<script lang="ts">
export let short = false;
interface Props {
short?: boolean;
}
let { short = false }: Props = $props();
</script>
<div class="wordmark">

View file

@ -1,16 +1,16 @@
import { env } from '$env/dynamic/public';
import { PUBLIC_REGARD24_HOST, PUBLIC_REGARD24_SITE, PUBLIC_DIRECTUS_HOST, PUBLIC_TELEGRAM_NEWSFEED } from '$env/static/public';
const Parameters = {
regard24: {
host: env.PUBLIC_REGARD24_HOST || 'https://comments.pupraider.net',
site: env.PUBLIC_REGARD24_SITE || 'devraider'
host: PUBLIC_REGARD24_HOST || 'https://comments.pupraider.net',
site: PUBLIC_REGARD24_SITE || 'devraider'
},
directus: {
base: env.PUBLIC_DIRECTUS_HOST || 'https://data.pupraider.net'
base: PUBLIC_DIRECTUS_HOST || 'https://data.pupraider.net'
},
social: {
telegram: {
newsfeedUsername: env.PUBLIC_TELEGRAM_NEWSFEED || 'raiderblog'
newsfeedUsername: PUBLIC_TELEGRAM_NEWSFEED || 'raiderblog'
}
}
};

View file

@ -1,6 +1,6 @@
import { env } from '$env/dynamic/public';
import { PUBLIC_BASE_URL } from '$env/static/public';
export const baseUrl = env.PUBLIC_BASE_URL || 'https://pupraider.net';
export const baseUrl = PUBLIC_BASE_URL || 'https://pupraider.net';
export const makeCanonicalUrl = (path: string) => {
if (!path.startsWith('/')) path = '/' + path;

View file

@ -1,16 +1,16 @@
import { env } from '$env/dynamic/private';
import { GHOST_URL, GHOST_CONTENT_TOKEN, GHOST_ADMIN_TOKEN, INSTAGRAM_TOKEN, INSTAGRAM_USERNAME } from '$env/static/private';
const Secrets = {
ghost: {
url: env.GHOST_URL || 'https://demo.ghost.io',
contentToken: env.GHOST_CONTENT_TOKEN || '22444f78447824223cefc48062',
url: GHOST_URL || 'https://demo.ghost.io',
contentToken: GHOST_CONTENT_TOKEN || '22444f78447824223cefc48062',
adminToken:
env.GHOST_ADMIN_TOKEN ||
GHOST_ADMIN_TOKEN ||
'1efedd9db174adee2d23d982:4b74dca0219bad629852191af326a45037346c2231240e0f7aec1f9371cc14e8'
},
instagram: {
token: env.INSTAGRAM_TOKEN || null,
username: env.INSTAGRAM_USERNAME || null
token: INSTAGRAM_TOKEN || null,
username: INSTAGRAM_USERNAME || null
}
};

View file

@ -47,11 +47,11 @@ export const load: PageServerLoad = async ({ params }) => {
}
maxPage = Math.ceil((author.data.count?.posts || 0) / limit);
} catch (e) {
throw error(404, 'Author not found');
error(404, 'Author not found');
}
if (page > maxPage) {
throw error(404, 'Page not found');
error(404, 'Page not found');
}
return {

View file

@ -5,7 +5,11 @@
import Seo from '$lib/components/SEO/SEO.svelte';
import { makeCanonicalUrl } from '$lib/seoUtils';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
</script>
<Seo
@ -58,10 +62,10 @@
{#if data.author.cover_image}
<img src={data.author.cover_image} alt={'Feature Image'} />
{:else}
<div class="img-placeholder" />
<div class="img-placeholder"></div>
{/if}
</figure>
<div class="fade" />
<div class="fade"></div>
<div class="header">
{#if data.author.profile_image}

View file

@ -3,7 +3,11 @@
import { makeCanonicalUrl } from '$lib/seoUtils';
import type { PageData } from './$types';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
</script>
<Seo

View file

@ -28,7 +28,7 @@ export const GET: RequestHandler = async (request) => {
if (!tag.success) {
console.error(tag.errors);
throw error(404, 'Topic not found');
error(404, 'Topic not found');
}
feedName = `${tag.data.name} on Raider's Blog`;
@ -54,7 +54,7 @@ export const GET: RequestHandler = async (request) => {
.fetch();
if (!posts.success) {
throw error(500, 'Unable to load posts');
error(500, 'Unable to load posts');
}
const feed = new Feed({
@ -120,5 +120,5 @@ export const GET: RequestHandler = async (request) => {
}
});
}
throw error(404, 'Invalid format');
error(404, 'Invalid format');
};

View file

@ -30,7 +30,7 @@ export const load: PageServerLoad = async () => {
}
} catch (e) {
console.error(e);
throw error(404, 'Topic not found');
error(404, 'Topic not found');
}
return {

View file

@ -6,7 +6,11 @@
import { makeCanonicalUrl } from '$lib/seoUtils';
import { Rss } from 'lucide-svelte';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
</script>
<Seo

View file

@ -27,7 +27,7 @@ export const load: PageServerLoad = async ({ params }) => {
throw 'Not Found';
}
} catch (e) {
throw error(404, 'Post not found');
error(404, 'Post not found');
}
const pubYear = post.data.published_at
@ -35,7 +35,7 @@ export const load: PageServerLoad = async ({ params }) => {
: 'other';
if (pubYear != params.year) {
throw redirect(301, `/read/${pubYear}/${params.slug}`);
redirect(301, `/read/${pubYear}/${params.slug}`);
}
return {

View file

@ -1,4 +1,6 @@
<script lang="ts">
import { run } from 'svelte/legacy';
/* eslint svelte/no-at-html-tags: "off" */
import type { PageData } from './$types';
import { DateTime } from 'luxon';
@ -9,7 +11,11 @@
import Parameters from '$lib/parameters';
import { siTelegram } from 'simple-icons';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
onMount(() => {
const interval = setInterval(() => {
@ -28,15 +34,15 @@
}
};
let commentFrame: HTMLIFrameElement;
let commentFrame: HTMLIFrameElement = $state();
$: {
run(() => {
if (commentFrame) {
recalculateFrameHeights();
}
}
});
$: publishTime = DateTime.fromISO(data.post.published_at || data.post.created_at || '2001-11-03');
let publishTime = $derived(DateTime.fromISO(data.post.published_at || data.post.created_at || '2001-11-03'));
</script>
<Seo
@ -154,7 +160,7 @@
title="Comment Section"
frameborder="0"
scrolling="no"
/>
></iframe>
</div>
</div>

View file

@ -23,7 +23,7 @@ export const load: PageServerLoad = async ({ params }) => {
throw 'Not Found';
}
} catch (e) {
throw error(404, 'Post not found');
error(404, 'Post not found');
}
const pubYear = post.data.published_at
@ -31,7 +31,7 @@ export const load: PageServerLoad = async ({ params }) => {
: 'other';
if (pubYear != params.year) {
throw redirect(301, `/read/${pubYear}/${params.slug}`);
redirect(301, `/read/${pubYear}/${params.slug}`);
}
return {

View file

@ -5,9 +5,13 @@
import { DateTime } from 'luxon';
import type { PageData } from './$types';
export let data: PageData;
interface Props {
data: PageData;
}
$: publishTime = DateTime.fromISO(data.post.published_at || data.post.created_at || '2001-11-03');
let { data }: Props = $props();
let publishTime = $derived(DateTime.fromISO(data.post.published_at || data.post.created_at || '2001-11-03'));
</script>
<h2>Comments</h2>

View file

@ -29,7 +29,7 @@ export const load: PageServerLoad = async ({ params }) => {
throw 'Not Found';
}
} catch (e) {
throw error(404, 'Page not found');
error(404, 'Page not found');
}
return {

View file

@ -7,9 +7,13 @@
import Seo from '$lib/components/SEO/SEO.svelte';
import { makeCanonicalUrl } from '$lib/seoUtils';
export let data: PageData;
interface Props {
data: PageData;
}
$: publishTime = DateTime.fromISO(data.post.published_at || data.post.created_at || '2001-11-03');
let { data }: Props = $props();
let publishTime = $derived(DateTime.fromISO(data.post.published_at || data.post.created_at || '2001-11-03'));
</script>
<Seo
@ -63,7 +67,7 @@
<img src={author.profile_image} alt={author.name + "'s portrait"} />
{/if}
{#if !author.profile_image}
<div class="photo-placeholder" />
<div class="photo-placeholder"></div>
{/if}
</div>
<div class="meta">

View file

@ -43,11 +43,11 @@ export const load: PageServerLoad = async ({ params }) => {
}
maxPage = Math.ceil((tag.data.count?.posts || 0) / limit);
} catch (e) {
throw error(404, 'Topic not found');
error(404, 'Topic not found');
}
if (page > maxPage) {
throw error(404, 'Page not found');
error(404, 'Page not found');
}
return {

View file

@ -5,7 +5,11 @@
import Seo from '$lib/components/SEO/SEO.svelte';
import { makeCanonicalUrl } from '$lib/seoUtils';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
</script>
<Seo
@ -42,10 +46,10 @@
{#if data.tag.feature_image}
<img src={data.tag.feature_image} alt={'Feature Image'} />
{:else}
<div class="img-placeholder" />
<div class="img-placeholder"></div>
{/if}
</figure>
<div class="fade" />
<div class="fade"></div>
<div class="header">
<h1>{data.tag.name}</h1>

View file

@ -20,11 +20,11 @@ export const load: PageServerLoad = async ({ params }) => {
throw 'Not Found';
}
} catch (e) {
throw error(404, 'Page not found');
error(404, 'Page not found');
}
if (!page) {
throw error(404, 'Page not found');
error(404, 'Page not found');
}
return {

View file

@ -5,7 +5,11 @@
import type { PageData } from './$types';
import { fly } from 'svelte/transition';
export let data: PageData;
interface Props {
data: PageData;
}
let { data }: Props = $props();
</script>
<Seo

View file

@ -1,20 +1,33 @@
<script lang="ts">
import { run } from 'svelte/legacy';
//import type { LayoutData } from './$types';
import { AreaChart, Moon, Rss, Sun } from 'lucide-svelte';
import '../../app.scss';
import { currentColorMode, effectiveColorMode, saveColorMode } from '$lib/colorMode';
import { onMount } from 'svelte';
import { dev } from '$app/environment';
interface Props {
children?: import('svelte').Snippet;
}
let root: HTMLElement;
let { children }: Props = $props();
let root: HTMLElement = $state();
onMount(() => {
root = document.documentElement;
});
$: root && root.classList.toggle('color-dark', $currentColorMode == 'dark');
$: root && root.classList.toggle('color-light', $currentColorMode == 'light');
$: root && root.classList.toggle('color-follow-system', $currentColorMode == 'follow-system');
run(() => {
root && root.classList.toggle('color-dark', $currentColorMode == 'dark');
});
run(() => {
root && root.classList.toggle('color-light', $currentColorMode == 'light');
});
run(() => {
root && root.classList.toggle('color-follow-system', $currentColorMode == 'follow-system');
});
//export let data: LayoutData;
</script>
@ -29,7 +42,7 @@
<a href="/read">Blog</a>
<button
on:click={() => {
onclick={() => {
saveColorMode($effectiveColorMode == 'light' ? 'dark' : 'light');
}}
>
@ -40,10 +53,10 @@
{/if}
</button>
</nav>
<div class="trailing-fill" />
<div class="trailing-fill"></div>
</div>
<main>
<slot />
{@render children?.()}
</main>
<footer>
<span class="attribution"

View file

@ -17,7 +17,7 @@
let isFromNFC =
typeof location === 'undefined' ? false : location?.href.indexOf('utm_medium=nfc') > -1;
let portraitImg: HTMLImageElement | null = null;
let portraitImg: HTMLImageElement | null = $state(null);
const performWoof = (/*i: number*/) => {
if (!portraitImg) return;
@ -111,20 +111,20 @@
<div class="portrait">
<div class="portrait-wrapper" class:barking={$barking}>
<button
on:click={() => {
onclick={() => {
bark('portrait', { barkCallback: performWoof });
}}
>
<img src={portrait} alt="Portrait of Pup Raider" bind:this={portraitImg} />
</button>
</div>
<div class="dummy-portrait" />
<div class="dummy-portrait"></div>
</div>
<div class="profile">
<div class="pattern-area" />
<div class="pattern-area"></div>
<WordMark />
<div class="line" />
<div class="line"></div>
<div class="linkies">
<a href="https://t.me/pup_raider" target="_blank" rel="noopener me">
{@html siTelegram.svg}
@ -140,7 +140,7 @@
</a>
</div>
<div class="pattern-area" />
<div class="pattern-area"></div>
</div>
</div>
@ -152,7 +152,7 @@
<div class="intro">
<h2>
<button on:click={() => bark('hidden_button', { barkCallback: performWoof })}>Woof</button>,
<button onclick={() => bark('hidden_button', { barkCallback: performWoof })}>Woof</button>,
I'm Raider 🐾
</h2>

View file

@ -8,8 +8,12 @@
import { onMount } from 'svelte';
import { CachePolicy, graphql } from '$houdini';
export let data: PageData;
$: ({GetEpisodeQuery} = data)
interface Props {
data: PageData;
}
let { data }: Props = $props();
let {GetEpisodeQuery} = $derived(data)
onMount(() => {
tokenStore.subscribe(() => {
@ -27,14 +31,14 @@
}
`)
let fetchingNextPage = false;
let fetchingNextPage = $state(false);
let sendingResponse = false;
let sendingResponse = $state(false);
let responseName = "";
let responseText = "";
let responseName = $state("");
let responseText = $state("");
let newestResponse: HTMLElement;
let newestResponse: HTMLElement = $state();
</script>
<Seo
@ -57,7 +61,7 @@
<h2>Share your response</h2>
<AuthenticateNag>
<form class="add-response" on:submit={async () => {
<form class="add-response" onsubmit={async () => {
sendingResponse = true;
try {
@ -93,7 +97,7 @@
<textarea id="body" placeholder="Your response here..." required bind:value={responseText} disabled={sendingResponse}></textarea>
</div>
<p>Please do not put any private information in these fields. Your response will be shown publically to other visitors.<br/>
We do not collect any personal data. We only keep an anonymous identifier you can <button class="reset" on:click={() => {
We do not collect any personal data. We only keep an anonymous identifier you can <button class="reset" onclick={() => {
setBearer(null)
}} disabled={sendingResponse}>reset here</button>.</p>
@ -106,7 +110,7 @@
<div class="responses">
{#each $GetEpisodeQuery.data?.episode?.answers.edges||[] as answer, idx}
{#if idx == 0}
<div class="jump-here" bind:this={newestResponse} />
<div class="jump-here" bind:this={newestResponse}></div>
{/if}
{#if answer}
<Answer episode={$GetEpisodeQuery.data?.episode?.id} answer={answer.node} admin={$GetEpisodeQuery.data?.self?.admin}
@ -119,7 +123,7 @@
{/if}
{/each}
{#if $GetEpisodeQuery.pageInfo.hasNextPage}
<button on:click={async () => {
<button onclick={async () => {
fetchingNextPage = true;
try {

View file

@ -159,7 +159,7 @@
<h3>Raider Stripes</h3>
<div class="pattern pattern-stripes" />
<div class="pattern pattern-stripes"></div>
<dl class="pattern-info">
<dt>Colors</dt>

View file

@ -12,7 +12,7 @@
/>
<div class="container">
<button class="woof" on:click={() => bark('woof_btn')}>Woof 🐶</button>
<button class="woof" onclick={() => bark('woof_btn')}>Woof 🐶</button>
</div>
<style lang="scss">

View file

@ -1,5 +1,5 @@
import adapter from '@sveltejs/adapter-auto';
import preprocess from 'svelte-preprocess';
import adapter from '@sveltejs/adapter-cloudflare';
import { sveltePreprocess } from 'svelte-preprocess';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
@ -8,7 +8,7 @@ const config = {
// for more information about preprocessors
preprocess: [
vitePreprocess(),
preprocess({
sveltePreprocess({
scss: {
prependData: '@use "src/variables.scss" as *;'
},