Compare commits
12 commits
0b6ebaef74
...
dcd386ad86
Author | SHA1 | Date | |
---|---|---|---|
dcd386ad86 | |||
a44e7c9594 | |||
0b19232800 | |||
8daffd6fc1 | |||
a21ee63baa | |||
5445f19c37 | |||
3bdc7d3f5e | |||
ea334128f6 | |||
1973d1a2df | |||
f7b786805b | |||
570c4a6e09 | |||
20de6e7133 |
38 changed files with 3167 additions and 1587 deletions
4294
package-lock.json
generated
4294
package-lock.json
generated
File diff suppressed because it is too large
Load diff
34
package.json
34
package.json
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>'
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<script lang="ts">
|
||||
export let short = false;
|
||||
interface Props {
|
||||
short?: boolean;
|
||||
}
|
||||
|
||||
let { short = false }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="wordmark">
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 *;'
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue