diff options
| author | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2021-04-15 23:06:26 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <ruben@unlimited.pizza> | 2021-04-15 23:06:26 +0200 |
| commit | 58f7d52150456713d3132408668a92d0f6f3d084 (patch) | |
| tree | 4b346042a684e416e53c4f4ac779060b832ad227 /src | |
| parent | 63c3da2af27fcfb1a9893ade03543e3a30949c8d (diff) | |
Port to sveltekit
Diffstat (limited to 'src')
46 files changed, 950 insertions, 827 deletions
diff --git a/src/animations/blink.js b/src/animations/blink.js index eeed3de..5515bb6 100644 --- a/src/animations/blink.js +++ b/src/animations/blink.js @@ -14,10 +14,10 @@ export const blink = function whoosh(node, params) { const halfWidth = originalWidth / 2; const halfHeight = originalHeight / 2; // const padding = t < 0.8 ? halfWidth * (1 - t) / 0.8 : halfWidth / 2 + 1; - const height = t <= 0.2 ? (originalHeight * t / 0.2) : originalHeight; - const marginY = t <= 0.2 ? (halfHeight * (1 - t / 0.2)) : 0; + const height = t <= 0.2 ? (originalHeight * t) / 0.2 : originalHeight; + const marginY = t <= 0.2 ? halfHeight * (1 - t / 0.2) : 0; const width = t > 0.2 ? ((t - 0.2) / 0.8) * originalWidth : 0; - const marginX = t > 0.2 ? (1 - ((t - 0.2) / 0.8)) * halfWidth : halfWidth; + const marginX = t > 0.2 ? (1 - (t - 0.2) / 0.8) * halfWidth : halfWidth; return `width: ${width}px; height: ${height}px; margin: ${marginY}px ${marginX}px`; } diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..1d7e288 --- /dev/null +++ b/src/app.css @@ -0,0 +1,4 @@ +:root { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, + 'Open Sans', 'Helvetica Neue', sans-serif; +} diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..062ed0f --- /dev/null +++ b/src/app.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <link rel="icon" href="/favicon.ico" /> + <meta name="description" content="A forum for the year 3000" /> + <meta name="robots" content="noindex, nofollow" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <meta name="theme-color" content="#ffffff" /> + + %svelte.head% + + <link rel="manifest" href="/manifest.webmanifest" /> + <link rel="stylesheet" href="/global.css" /> + </head> + <body> + <noscript> + <h1>Javascript Required.</h1> + <p>Please enable Javascript to use this forum.</p> + </noscript> + <div id="forum">%svelte.body%</div> + </body> +</html> diff --git a/src/components/error_block/error_block.svelte b/src/components/error_block/error_block.svelte index b85a2ea..3a43a1e 100644 --- a/src/components/error_block/error_block.svelte +++ b/src/components/error_block/error_block.svelte @@ -1,38 +1,40 @@ <script> - import { _ } from 'svelte-i18n'; - export let message; + import { _ } from 'svelte-i18n'; + export let message; - import { blink } from '$/animations/blink'; + import { blink } from '$/animations/blink'; </script> <div transition:blink> - <h2>{$_('error.generic.title')}</h2> - <p>{message || $_('error.generic.message')}</p> + <h2>{$_('error.generic.title')}</h2> + <p>{message || $_('error.generic.message')}</p> </div> <style> - div { - background: repeating-linear-gradient( -45deg, red, red 5px, black 5px, black 10px ); - border: 5px solid red; - color: yellow; - font-family: 'ヒラギノ角ゴ ProN' , 'Hiragino Kaku Gothic ProN' , '游ゴシック' , '游ゴシック体' , YuGothic , 'Yu Gothic' , 'メイリオ' , Meiryo , 'MS ゴシック' , 'MS Gothic' , HiraKakuProN-W3 , 'TakaoExゴシック' , TakaoExGothic , 'MotoyaLCedar' , 'Droid Sans Japanese' , sans-serif; - margin: 0 10px 0 0; - text-align: center; - overflow: hidden; - } + div { + background: repeating-linear-gradient(-45deg, red, red 5px, black 5px, black 10px); + border: 5px solid red; + color: yellow; + font-family: 'ヒラギノ角ゴ ProN', 'Hiragino Kaku Gothic ProN', '游ゴシック', '游ゴシック体', + YuGothic, 'Yu Gothic', 'メイリオ', Meiryo, 'MS ゴシック', 'MS Gothic', HiraKakuProN-W3, + 'TakaoExゴシック', TakaoExGothic, 'MotoyaLCedar', 'Droid Sans Japanese', sans-serif; + margin: 0 10px 0 0; + text-align: center; + overflow: hidden; + } - h2, p { - background-color: black; - font-size: 1em; - } + h2, + p { + background-color: black; + font-size: 1em; + } - h2 { - text-transform: uppercase; - margin: 100px 5px 10px; - } + h2 { + text-transform: uppercase; + margin: 100px 5px 10px; + } - p { - margin: 10px 5px 100px; - } + p { + margin: 10px 5px 100px; + } </style> - diff --git a/src/components/footer/footer.svelte b/src/components/footer/footer.svelte index 317319e..2d5f8ff 100644 --- a/src/components/footer/footer.svelte +++ b/src/components/footer/footer.svelte @@ -1,36 +1,30 @@ <script> - import { _ } from 'svelte-i18n'; + import { _ } from 'svelte-i18n'; - import LanguageSelector from '$/components/language_selector/language_selector.svelte'; + import LanguageSelector from '$/components/language_selector/language_selector.svelte'; - const licenseUrl = 'https://gitlab.com/rbdr/forum/'; + const licenseUrl = 'https://gitlab.com/rbdr/forum/'; </script> -<footer title="{$_('footer.title')}"> - <ul> - <li>{@html $_('footer.license', { values: { licenseUrl } })}</li> - <li>{$_('footer.choose_language')}: <LanguageSelector /></li> - </ul> +<footer title={$_('footer.title')}> + <ul> + <li>{@html $_('footer.license', { values: { licenseUrl } })}</li> + <li>{$_('footer.choose_language')}: <LanguageSelector /></li> + </ul> </footer> <style> - footer { - grid-column: col-start 1 / span 12; - border-top: 1px solid black; - } + footer { + grid-column: col-start 1 / span 12; + border-top: 1px solid black; + } - ul { - padding: 0; - } + ul { + padding: 0; + } - li { - display: inline; - margin: 5px; - } - - a { - text-decoration: none; - line-height: 3em; - display: inline-block; - } + li { + display: inline; + margin: 5px; + } </style> diff --git a/src/components/forum/forum.svelte b/src/components/forum/forum.svelte index 8fc0538..ea9b206 100644 --- a/src/components/forum/forum.svelte +++ b/src/components/forum/forum.svelte @@ -1,28 +1,13 @@ <script> - export let id; + export let forum; - import { _ } from 'svelte-i18n'; - import { getForum } from '$/stores/forum'; - import ErrorBlock from '$/components/error_block/error_block.svelte'; - import Loader from '$/components/loader/loader.svelte'; - - import TopicSummary from '$/components/topic_summary/topic_summary.svelte'; - - $: store = getForum(id); - $: forum = $store.data; + import { _ } from 'svelte-i18n'; + import TopicSummary from '$/components/topic_summary/topic_summary.svelte'; </script> -{#if $store.loading} - <Loader /> -{/if} -{#if $store.error} - <ErrorBlock message={$_('forum.error.unavailable')} /> -{/if} -{#if forum} - <h1>{forum.glyph} {$_(forum.label)}</h1> - <ul> - {#each forum.topics as topic} - <TopicSummary topic={topic} /> - {/each} - </ul> -{/if} +<h1>{forum.glyph} {$_(forum.label)}</h1> +<ul> + {#each forum.topics as topic} + <TopicSummary {topic} /> + {/each} +</ul> diff --git a/src/components/forum_list/forum_list.svelte b/src/components/forum_list/forum_list.svelte index 2998c09..7bfb7b2 100644 --- a/src/components/forum_list/forum_list.svelte +++ b/src/components/forum_list/forum_list.svelte @@ -1,56 +1,56 @@ <script> - import { _ } from 'svelte-i18n'; - import { forums } from '$/stores/forums'; - import Loader from '$/components/loader/loader.svelte'; - import ErrorBlock from '$/components/error_block/error_block.svelte'; + import { _ } from 'svelte-i18n'; + import { forums } from '$/stores/forums'; + import Loader from '$/components/loader/loader.svelte'; + import ErrorBlock from '$/components/error_block/error_block.svelte'; </script> -<nav title="{$_('forum_list.title')}"> - {#if $forums.loading} - <Loader /> - {/if} - {#if $forums.error} - <ErrorBlock message={$_('forum_list.error.unavailable')} /> - {/if} - <ul> - {#each $forums.data as forum} - <li> - <a href="/f/{forum.id}"> - <span aria-hidden="true" class="navigation-glyph {forum.glyph}">{forum.glyph}</span> - <span class="navigation-label">{$_(forum.label)}</span> - </a> - </li> - {/each} - </ul> +<nav title={$_('forum_list.title')}> + {#if $forums.loading} + <Loader /> + {/if} + {#if $forums.error} + <ErrorBlock message={$_('forum_list.error.unavailable')} /> + {/if} + <ul> + {#each $forums.data as forum} + <li> + <a href="/f/{forum.id}"> + <span aria-hidden="true" class="navigation-glyph {forum.glyph}">{forum.glyph}</span> + <span class="navigation-label">{$_(forum.label)}</span> + </a> + </li> + {/each} + </ul> </nav> <style> - nav { - grid-column: col-start 1; - grid-row: 2; - border-right: 1px solid black; - } + nav { + grid-column: col-start 1; + grid-row: 2; + border-right: 1px solid black; + } - ul { - padding: 0; - } + ul { + padding: 0; + } - li { - display: block; - text-align: left; - margin-bottom: 20px; - } + li { + display: block; + text-align: left; + margin-bottom: 20px; + } - .navigation-glyph { - font-size: 1.5rem; - display: block; - } + .navigation-glyph { + font-size: 1.5rem; + display: block; + } - .☽ { - font-size: 2rem; - } + .☽ { + font-size: 2rem; + } - a { - text-decoration: none; - } + a { + text-decoration: none; + } </style> diff --git a/src/components/glyph/glyph.svelte b/src/components/glyph/glyph.svelte index 32e8ee6..e430d42 100644 --- a/src/components/glyph/glyph.svelte +++ b/src/components/glyph/glyph.svelte @@ -1,41 +1,41 @@ <script> - import { _ } from 'svelte-i18n'; - import { getGlyphHash } from '$/utils/glyph_hash'; + import { _ } from 'svelte-i18n'; + import { getGlyphHash } from '$/utils/glyph_hash'; - export let uuid; + export let uuid; </script> -<div class="glyphicon" aria-hidden="true" title="{$_('glyph.title')}"> - {#each getGlyphHash(uuid) as fragment} - <span class="{fragment.glyph}" style="color: {fragment.color} "> - {fragment.glyph} - </span> - {/each} +<div class="glyphicon" aria-hidden="true" title={$_('glyph.title')}> + {#each getGlyphHash(uuid) as fragment} + <span class={fragment.glyph} style="color: {fragment.color} "> + {fragment.glyph} + </span> + {/each} </div> <style> - .glyphicon { - border: 1px solid black; - display: inline-block; - font-size: 1.4rem; - height: 48px; - margin-top: 5px; - width: 48px; - background-color: white; - padding: 2px; - } + .glyphicon { + border: 1px solid black; + display: inline-block; + font-size: 1.4rem; + height: 48px; + margin-top: 5px; + width: 48px; + background-color: white; + padding: 2px; + } - span { - display: block; - float: left; - width: 24px; - height: 24px; - text-align: center; - line-height: 24px; - } + span { + display: block; + float: left; + width: 24px; + height: 24px; + text-align: center; + line-height: 24px; + } - .☽ { - font-size: 2rem; - line-height: 19px; - } + .☽ { + font-size: 2rem; + line-height: 19px; + } </style> diff --git a/src/components/header/header.svelte b/src/components/header/header.svelte index c68a685..f33e77b 100644 --- a/src/components/header/header.svelte +++ b/src/components/header/header.svelte @@ -1,51 +1,68 @@ <script> - import { _ } from 'svelte-i18n'; + import { _ } from 'svelte-i18n'; + import { version } from '$/config/config'; + import { actions } from '$/stores/actions'; - import { params } from '@roxi/routify'; - import { version } from '$/config/config'; + $: topic_id = $actions.topic_id; </script> -<header title="{$_('header.title')}"> - <ul> - <li><strong><a href="/" aria-label="{$_('header.long_version', { values: { version } })}">{$_('header.short_version', { values: { version } })}</a></strong></li> - <li><a href="/new" aria-label="{$_('header.action.new.title')}">{@html $_('header.action.new.display')}</a></li> - {#if $params.topic_id} - <li><a href="/reply/{$params.topic_id}" aria-label="{$_('header.action.reply.title')}">{@html $_('header.action.reply.display')}</a></li> - {/if} - <li><a href="/search" aria-label="{$_('header.action.search.title')}">{@html $_('header.action.search.display')}</a></li> - <li><a href="/logout" aria-label="{$_('header.action.log_out.title')}">{@html $_('header.action.log_out.display')}</a></li> - </ul> +<header title={$_('header.title')}> + <ul> + <li> + <strong + ><a href="/" aria-label={$_('header.long_version', { values: { version } })} + >{$_('header.short_version', { values: { version } })}</a + ></strong + > + </li> + <li> + <a href="/new" aria-label={$_('header.action.new.title')} + >{@html $_('header.action.new.display')}</a + > + </li> + {#if topic_id} + <li> + <a href="/reply/{topic_id}" aria-label={$_('header.action.reply.title')} + >{@html $_('header.action.reply.display')}</a + > + </li> + {/if} + <li> + <a href="/search" aria-label={$_('header.action.search.title')} + >{@html $_('header.action.search.display')}</a + > + </li> + <li> + <a href="/logout" aria-label={$_('header.action.log_out.title')} + >{@html $_('header.action.log_out.display')}</a + > + </li> + </ul> </header> <style> - header { - grid-column: col-start 1 / span 12; - border-bottom: 1px solid black; - } + header { + grid-column: col-start 1 / span 12; + border-bottom: 1px solid black; + } - ul { - padding: 0; - } + ul { + padding: 0; + } - .action-key { - font-weight: bold; - text-decoration: underline; - } + li { + display: inline; + margin: 5px; + } - li { - display: inline; - margin: 5px; - } - - a { - text-decoration: none; - line-height: 3em; - display: inline-block; - } - - strong a { - color: blue; - text-decoration: underline; - } + a { + text-decoration: none; + line-height: 3em; + display: inline-block; + } + strong a { + color: blue; + text-decoration: underline; + } </style> diff --git a/src/components/home/home.svelte b/src/components/home/home.svelte index 7000137..fa4a70e 100644 --- a/src/components/home/home.svelte +++ b/src/components/home/home.svelte @@ -1,5 +1,5 @@ <script> - import { _ } from 'svelte-i18n'; + import { _ } from 'svelte-i18n'; </script> <h1>{$_('home.title')}</h1> diff --git a/src/components/invalid_route/invalid_route.svelte b/src/components/invalid_route/invalid_route.svelte index aaf7927..2a3686c 100644 --- a/src/components/invalid_route/invalid_route.svelte +++ b/src/components/invalid_route/invalid_route.svelte @@ -1,5 +1,5 @@ <script> - import { _ } from 'svelte-i18n'; + import { _ } from 'svelte-i18n'; </script> <h1>{$_('error.invalid_url.title')}</h1> diff --git a/src/components/language_selector/language_selector.svelte b/src/components/language_selector/language_selector.svelte index 3ac4894..3338810 100644 --- a/src/components/language_selector/language_selector.svelte +++ b/src/components/language_selector/language_selector.svelte @@ -1,28 +1,27 @@ <script> - import { locale, locales } from 'svelte-i18n'; - import { getLangNameFromCode } from 'language-name-map'; + import { locale, locales } from 'svelte-i18n'; + import { getLangNameFromCode } from 'language-name-map'; - $: namedLocales = $locales - .map((code) => ({ - code, - ...getLangNameFromCode(code) - })) - .sort((a, b) => a.native - b.native); + $: namedLocales = $locales + .map((code) => ({ + code, + ...getLangNameFromCode(code) + })) + .sort((a, b) => a.native - b.native); - let selected = $locale; + let selected = $locale; - $: { - console.log(`the current locale is ${selected}`); - locale.set(selected); - } + $: { + console.log(`the current locale is ${selected}`); + locale.set(selected); + } </script> <select bind:value={selected}> - {#each namedLocales as namedLocale} - <option value="{ namedLocale.code }">{ namedLocale.native }</option> - {/each} + {#each namedLocales as namedLocale} + <option value={namedLocale.code}>{namedLocale.native}</option> + {/each} </select> <style> </style> - diff --git a/src/components/loader/loader.svelte b/src/components/loader/loader.svelte index e9787aa..8d53736 100644 --- a/src/components/loader/loader.svelte +++ b/src/components/loader/loader.svelte @@ -1,5 +1,5 @@ <script> - import { _ } from 'svelte-i18n'; + import { _ } from 'svelte-i18n'; </script> <p>{$_('loader.message')}</p> diff --git a/src/components/post/post.svelte b/src/components/post/post.svelte index bf2a190..5d8ef1c 100644 --- a/src/components/post/post.svelte +++ b/src/components/post/post.svelte @@ -1,23 +1,50 @@ <script> - export let id; + export let post; + export let index = 0; + export let count = 1; - import { _ } from 'svelte-i18n'; + import { _ } from 'svelte-i18n'; + import Glyph from '$/components/glyph/glyph.svelte'; - import { getPost } from '$/stores/post'; - import PostContent from '$/components/post_content/post_content.svelte'; - import ErrorBlock from '$/components/error_block/error_block.svelte'; - import Loader from '$/components/loader/loader.svelte'; - - $: store = getPost(id); - $: post = $store.data; + const timestampToISO = (timestamp) => new Date(timestamp).toISOString(); </script> -{#if $store.loading} - <Loader /> -{/if} -{#if $store.error} - <ErrorBlock message={$_('post.error.unavailable')} /> -{/if} -{#if post} - <PostContent post={post} /> -{/if} +<aside + class="post-meta" + title={$_('post.metadata_title', { values: { count: index + 1, total: count } })} +> + <Glyph uuid={post.author.id} /> + <span class="h-card"> + {$_('post.author_credit')} + <a href="/a/{post.author.handle}" class="p-nickname u-url">{post.author.handle}</a>. + </span> + <time role="presentation" class="dt-published" datetime={timestampToISO(post.created_at)}> + <a title={$_('post.permalink_title')} href="/p/{post.id}"> + {timestampToISO(post.created_at)} + </a> + </time> + {#if post.topic} + <span class="h-card"> + ({$_('post.topic_location')} <a href="/t/{post.topic.id}">{post.topic.title}</a>.) + </span> + {/if} +</aside> +<article + class="e-content" + title={$_('post.title', { + values: { count: index + 1, total: count, author: post.author.handle } + })} +> + {post.text} +</article> +<hr /> + +<style> + .post-meta * { + vertical-align: top; + } + + article { + white-space: pre; + } +</style> diff --git a/src/components/post_content/post_content.svelte b/src/components/post_content/post_content.svelte index 671c07c..5d8ef1c 100644 --- a/src/components/post_content/post_content.svelte +++ b/src/components/post_content/post_content.svelte @@ -1,40 +1,50 @@ <script> - export let post; - export let index = 0; - export let count = 1; + export let post; + export let index = 0; + export let count = 1; - import { _ } from 'svelte-i18n'; - import Glyph from '$/components/glyph/glyph.svelte'; + import { _ } from 'svelte-i18n'; + import Glyph from '$/components/glyph/glyph.svelte'; - const timestampToISO = (timestamp) => (new Date(timestamp)).toISOString(); + const timestampToISO = (timestamp) => new Date(timestamp).toISOString(); </script> - <aside class="post-meta" title="{$_('post.metadata_title', { values: { count: index + 1, total: count } })}"> - <Glyph uuid={post.author.id} /> - <span class="h-card"> - {$_('post.author_credit')} <a href="/a/{post.author.handle}" class="p-nickname u-url">{post.author.handle}</a>. - </span> - <time role="presentation" class="dt-published" datetime="{timestampToISO(post.created_at)}"> - <a title="{$_('post.permalink_title')}" href="/p/{post.id}"> - {timestampToISO(post.created_at)} - </a> - </time> - {#if post.topic} - <span class="h-card"> - ({$_('post.topic_location')} <a href="/t/{post.topic.id}">{post.topic.title}</a>.) - </span> - {/if} - </aside> - <article class="e-content" title="{$_('post.title', { values: { count: index + 1, total: count, author: post.author.handle } })}"> - {post.text} - </article> - <hr/> + +<aside + class="post-meta" + title={$_('post.metadata_title', { values: { count: index + 1, total: count } })} +> + <Glyph uuid={post.author.id} /> + <span class="h-card"> + {$_('post.author_credit')} + <a href="/a/{post.author.handle}" class="p-nickname u-url">{post.author.handle}</a>. + </span> + <time role="presentation" class="dt-published" datetime={timestampToISO(post.created_at)}> + <a title={$_('post.permalink_title')} href="/p/{post.id}"> + {timestampToISO(post.created_at)} + </a> + </time> + {#if post.topic} + <span class="h-card"> + ({$_('post.topic_location')} <a href="/t/{post.topic.id}">{post.topic.title}</a>.) + </span> + {/if} +</aside> +<article + class="e-content" + title={$_('post.title', { + values: { count: index + 1, total: count, author: post.author.handle } + })} +> + {post.text} +</article> +<hr /> <style> - .post-meta * { - vertical-align: top; - } + .post-meta * { + vertical-align: top; + } - article { - white-space: pre; - } + article { + white-space: pre; + } </style> diff --git a/src/components/tag/tag.svelte b/src/components/tag/tag.svelte index a14cd19..954cdaa 100644 --- a/src/components/tag/tag.svelte +++ b/src/components/tag/tag.svelte @@ -1,27 +1,13 @@ <script> - export let id; + export let tag; - import { _ } from 'svelte-i18n'; - import { getTag } from '$/stores/tag'; - import ErrorBlock from '$/components/error_block/error_block.svelte'; - import Loader from '$/components/loader/loader.svelte'; - import TopicSummary from '$/components/topic_summary/topic_summary.svelte'; - - $: store = getTag(id); - $: tag = $store.data; + import { _ } from 'svelte-i18n'; + import TopicSummary from '$/components/topic_summary/topic_summary.svelte'; </script> -{#if $store.loading} - <Loader /> -{/if} -{#if $store.error} - <ErrorBlock message={$_('tag.error.unavailable')} /> -{/if} -{#if tag} - <h1>{$_('tag.title')} {tag.id}</h1> - <ul> - {#each tag.topics as topic} - <TopicSummary topic={topic} /> - {/each} - </ul> -{/if} +<h1>{$_('tag.title')}: {tag.id}</h1> +<ul> + {#each tag.topics as topic} + <TopicSummary {topic} /> + {/each} +</ul> diff --git a/src/components/topic/topic.svelte b/src/components/topic/topic.svelte index 9be7346..181b429 100644 --- a/src/components/topic/topic.svelte +++ b/src/components/topic/topic.svelte @@ -1,46 +1,44 @@ <script> - export let id; + export let topic; - import { _ } from 'svelte-i18n'; - import { getTopic } from '$/stores/topic'; + import { _ } from 'svelte-i18n'; + import Post from '$/components/post/post.svelte'; + import { readableTime } from '$/utils/readable_time.js'; - import ErrorBlock from '$/components/error_block/error_block.svelte'; - import Loader from '$/components/loader/loader.svelte'; - import PostContent from '$/components/post_content/post_content.svelte'; - import { readableTime } from '$/utils/readable_time.js'; - - $: store = getTopic(id); - $: topic = $store.data; - $: remainingTime = topic ? (topic.updated_at + topic.ttl) - Date.now() : 0; - $: remaining = readableTime(remainingTime); + $: remainingTime = topic ? topic.updated_at + topic.ttl - Date.now() : 0; + $: remaining = readableTime(remainingTime); </script> -{#if $store.loading} - <Loader /> -{/if} -{#if $store.error} - <ErrorBlock message={$_('topic.error.unavailable')} /> -{/if} -{#if topic} - <div class="h-entry" title="{$_('topic.title')}"> - <h1 class="p-name">{topic.title}</h1> - <aside class="topic-meta" title="{$_('topic.metadata_title')}"> - {#if topic.forum} - <span class="topic-location">{$_('topic.category_location')} <a href="/f/{topic.forum.id}" - class="p-category">{topic.forum.glyph} {$_(topic.forum.label)}</a>.</span> - {/if} - <span class="topic-ttl"><a class="u-url u-uid" title="{$_('topic.permalink_title')}" href="/t/{topic.id}">({$_('topic.remaining_time', { values: { remaining: $_(remaining.label, { values: { count: remaining.count } }) } })})</a>.</span> - </aside> - {#if topic.tags.length > 0} - <aside class="topic-tags" title="{$_('topic.tags_title')}"> - {$_('topic.tags_location')} - {#each topic.tags as tag} - <a href="/g/{tag.id}" class="p-category">{tag.id}<span class="tag-weight">({tag.weight})</span></a>{' '} - {/each} - </aside> - {/if} - {#each topic.posts as post, index} - <PostContent post={post} index={index} count={topic.posts.length} /> - {/each} - </div> -{/if} +<div class="h-entry" title={$_('topic.title')}> + <h1 class="p-name">{topic.title}</h1> + <aside class="topic-meta" title={$_('topic.metadata_title')}> + {#if topic.forum} + <span class="topic-location" + >{$_('topic.category_location')} + <a href="/f/{topic.forum.id}" class="p-category" + >{topic.forum.glyph} {$_(topic.forum.label)}</a + >.</span + > + {/if} + <span class="topic-ttl" + ><a class="u-url u-uid" title={$_('topic.permalink_title')} href="/t/{topic.id}" + >({$_('topic.remaining_time', { + values: { remaining: $_(remaining.label, { values: { count: remaining.count } }) } + })})</a + >.</span + > + </aside> + {#if topic.tags.length > 0} + <aside class="topic-tags" title={$_('topic.tags_title')}> + {$_('topic.tags_location')} + {#each topic.tags as tag} + <a href="/g/{tag.id}" class="p-category" + >{tag.id}<span class="tag-weight">({tag.weight})</span></a + >{' '} + {/each} + </aside> + {/if} + {#each topic.posts as post, index} + <Post {post} {index} count={topic.posts.length} /> + {/each} +</div> diff --git a/src/components/topic_summary/topic_summary.svelte b/src/components/topic_summary/topic_summary.svelte index 88b2b83..5f2678b 100644 --- a/src/components/topic_summary/topic_summary.svelte +++ b/src/components/topic_summary/topic_summary.svelte @@ -1,16 +1,24 @@ <script> - export let topic; + export let topic; - import { _ } from 'svelte-i18n'; - import { readableTime } from '$/utils/readable_time.js'; + import { _ } from 'svelte-i18n'; + import { readableTime } from '$/utils/readable_time.js'; - $: remainingTime = (topic.updated_at + topic.ttl) - Date.now(); - $: remaining = readableTime(remainingTime); + $: remainingTime = topic.updated_at + topic.ttl - Date.now(); + $: remaining = readableTime(remainingTime); </script> -<li class="h-entry" title="{$_('topic.title')}"> - <span class="p-name"><a class="u-url u-uid" title="{$_('topic.permalink_title')}" href="/t/{topic.id}">{topic.title}</a></span> - <span class="topic-ttl">({$_('topic.remaining_time', { values: { remaining: $_(remaining.label, { values: { count: remaining.count } }) } })})</span> +<li class="h-entry" title={$_('topic.title')}> + <span class="p-name" + ><a class="u-url u-uid" title={$_('topic.permalink_title')} href="/t/{topic.id}" + >{topic.title}</a + ></span + > + <span class="topic-ttl" + >({$_('topic.remaining_time', { + values: { remaining: $_(remaining.label, { values: { count: remaining.count } }) } + })})</span + > </li> <style> diff --git a/src/config/apollo.js b/src/config/apollo.js index 4cfca79..a3820ed 100644 --- a/src/config/apollo.js +++ b/src/config/apollo.js @@ -1,9 +1,14 @@ -import { ApolloClient, InMemoryCache } from '@apollo/client/core'; +import fetch from 'cross-fetch'; +import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'; import { apollo as apolloConfig } from './config'; const cache = new InMemoryCache(); export const client = new ApolloClient({ cache, + link: new HttpLink({ + uri: apolloConfig.uri, + fetch + }), ...apolloConfig }); diff --git a/src/config/config.js b/src/config/config.js index 0570e1c..9d6d40e 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -7,9 +7,9 @@ import { name, version as packageVersion } from '../../package.json'; */ export const apollo = { - uri: import.meta.env.VITE_APOLLO_SERVER, - name, - version: packageVersion + uri: import.meta.env.VITE_APOLLO_SERVER, + name, + version: packageVersion }; export const socketServer = import.meta.env.FORUM_SOCKET_SERVER; diff --git a/src/config/translations/en.json b/src/config/translations/en.json index cf66bf2..14e89e4 100644 --- a/src/config/translations/en.json +++ b/src/config/translations/en.json @@ -1,110 +1,112 @@ { - "error": { - "generic": { - "title": "Error!", - "message": "Unknown error has occurred. Panic!" - }, - "invalid_url": { - "title": "This is not right.", - "message": "This URL is not valid. Try another one maybe?" - } - }, - "footer": { - "choose_language": "Choose your language", - "license": "Forum is <a href=\"{licenseUrl}\">open source.</a>", - "title": "Footer" - }, - "forum": { - "name": { - "everything": "Everything", - "us": "Us", - "words": "Words", - "sound": "Sounds", - "structure": "Structure", - "interaction": "Interaction", - "emotion": "Emotion", - "movement": "Movement", - "belief": "Belief", - "experience": "Experience", - "online": "Online", - "the_world": "The World", - "life": "Life" - }, - "error": { - "unavailable": "Forum topics unavailable." - } - }, - "forum_list": { - "title": "List of forums", - "error": { - "unavailable": "Forum list unavailable." - } - }, - "glyph": { - "title": "User avatar" - }, - "header": { - "action": { - "new": { - "title": "New", - "display": "<u>N</u>ew" - }, - "reply": { - "title": "Reply", - "display": "<u>R</u>eply" - }, - "search": { - "title": "Search", - "display": "<u>S</u>earch" - }, - "log_out": { - "title": "Log Out", - "display": "Log <u>O</u>ut" - } - }, - "long_version": "Forum version {version}", - "title": "Toolbar", - "short_version": "Forum v{version}" - }, - "home": { - "title": "Hello.", - "content": "You are now in a forum. Select a category from the left or input a valid URL." - }, - "loader": { - "message": "Loading." - }, - "post": { - "author_credit": "By:", - "metadata_title": "Post {count} of {total} metadata", - "permalink_title": "Permalink to post", - "title": "Post {count} of {total} by {author}", - "topic_location": "In", - "error": { - "unavailable": "Post unavailable." - } - }, - "tag": { - "title": "Tag:", - "error": { - "unavailable": "Tag topics unavailable." - } - }, - "topic": { - "category_location": "Posted on", - "metadata_title": "Topic metadata", - "permalink_title": "Permalink to topic", - "remaining_time": "{remaining} remaining", - "tags_location": "Tags:", - "tags_title": "Topic tags", - "title": "Topic", - "error": { - "unavailable": "Topic unavailable." - } - }, - "time": { - "days": "{count, plural, =1 {# day} other {# days}}", - "hours": "{count, plural, =1 {# hour} other {# hours}}", - "minutes": "{count, plural, =1 {# minute} other {# minutes}}", - "seconds": "{count, plural, =1 {# second} other {# seconds}}" - } + "error": { + "generic": { + "title": "Error!", + "message": "Unknown error has occurred. Panic!" + }, + "invalid_url": { + "title": "This is not right.", + "message": "This URL is not valid. Try another one maybe?" + } + }, + "footer": { + "choose_language": "Choose your language", + "license": "Forum is <a href=\"{licenseUrl}\">open source.</a>", + "title": "Footer" + }, + "forum": { + "forum": "forum", + "name": { + "everything": "Everything", + "us": "Us", + "words": "Words", + "sound": "Sounds", + "structure": "Structure", + "interaction": "Interaction", + "emotion": "Emotion", + "movement": "Movement", + "belief": "Belief", + "experience": "Experience", + "online": "Online", + "the_world": "The World", + "life": "Life" + }, + "error": { + "unavailable": "Forum topics unavailable." + } + }, + "forum_list": { + "title": "List of forums", + "error": { + "unavailable": "Forum list unavailable." + } + }, + "glyph": { + "title": "User avatar" + }, + "header": { + "action": { + "new": { + "title": "New", + "display": "<u>N</u>ew" + }, + "reply": { + "title": "Reply", + "display": "<u>R</u>eply" + }, + "search": { + "title": "Search", + "display": "<u>S</u>earch" + }, + "log_out": { + "title": "Log Out", + "display": "Log <u>O</u>ut" + } + }, + "long_version": "Forum version {version}", + "title": "Toolbar", + "short_version": "Forum v{version}" + }, + "home": { + "title": "Hello.", + "content": "You are now in a forum. Select a category from the left or input a valid URL." + }, + "loader": { + "message": "Loading." + }, + "post": { + "author_credit": "By:", + "metadata_title": "Post {count} of {total} metadata", + "permalink_title": "Permalink to post", + "post": "Post", + "title": "Post {count} of {total} by {author}", + "topic_location": "In", + "error": { + "unavailable": "Post unavailable." + } + }, + "tag": { + "title": "Tag", + "error": { + "unavailable": "Tag topics unavailable." + } + }, + "topic": { + "category_location": "Posted on", + "metadata_title": "Topic metadata", + "permalink_title": "Permalink to topic", + "remaining_time": "{remaining} remaining", + "tags_location": "Tags:", + "tags_title": "Topic tags", + "title": "Topic", + "error": { + "unavailable": "Topic unavailable." + } + }, + "time": { + "days": "{count, plural, =1 {# day} other {# days}}", + "hours": "{count, plural, =1 {# hour} other {# hours}}", + "minutes": "{count, plural, =1 {# minute} other {# minutes}}", + "seconds": "{count, plural, =1 {# second} other {# seconds}}" + } } diff --git a/src/config/translations/es.json b/src/config/translations/es.json index 6b6880f..4f6b0c1 100644 --- a/src/config/translations/es.json +++ b/src/config/translations/es.json @@ -1,110 +1,112 @@ { - "error": { - "generic": { - "title": "Error!", - "message": "Hubo un error desconocido. ¡Entra en pánico!" - }, - "invalid_url": { - "title": "Esto no está bien.", - "message": "Este URL no es válido. Intenta otro, ¿Tal vez?" - } - }, - "footer": { - "choose_language": "Escoge un lenguaje", - "license": "Forum es <a href=\"{licenseUrl}\">software libre.</a>", - "title": "Pie de página" - }, - "forum": { - "name": { - "everything": "Todo", - "us": "Nosotros", - "words": "Palabras", - "sound": "Sonidos", - "structure": "Estructura", - "interaction": "Interacción", - "emotion": "Emoción", - "movement": "Movimiento", - "belief": "Creencia", - "experience": "Experiencia", - "online": "En Línea", - "the_world": "El Mundo", - "life": "Vida" - }, - "error": { - "unavailable": "Temas del foro no disponibles." - } - }, - "forum_list": { - "title": "Lista de foros", - "error": { - "unavailable": "Lista de foros no disponible." - } - }, - "glyph": { - "title": "Avatar del usuario" - }, - "header": { - "action": { - "new": { - "title": "Nuevo", - "display": "<u>N</u>uevo" - }, - "reply": { - "title": "Responder", - "display": "<u>R</u>esponder" - }, - "search": { - "title": "Buscar", - "display": "Bu<u>s</u>car" - }, - "log_out": { - "title": "Cerrar Sesión", - "display": "Cerrar Sesi<u>ó</u>n" - } - }, - "long_version": "Forum versión {version}", - "title": "Barra de herramientas", - "short_version": "Forum v{version}" - }, - "home": { - "title": "Hola.", - "content": "Ahora estás en un foro. Elige una categoría de la izquierda o escribe un URL válido." - }, - "loader": { - "message": "Cargando." - }, - "post": { - "author_credit": "Por:", - "metadata_title": "Metadatos de entrada {count} de {total}", - "permalink_title": "Permalink a entrada", - "title": "Entrada {count} de {total}, por {author}", - "topic_location": "En", - "error": { - "unavailable": "Entrada no disponible." - } - }, - "tag": { - "title": "Etiqueta:", - "error": { - "unavailable": "Temas de la etiqueta no disponibles." - } - }, - "topic": { - "category_location": "Agregado a", - "metadata_title": "Metadatos del tema", - "permalink_title": "Permalink al tema", - "remaining_time": "Quedan {remaining}", - "tags_location": "Etiquetas:", - "tags_title": "Etiquetas del tema", - "title": "Tema", - "error": { - "unavailable": "Tema no disponible." - } - }, - "time": { - "days": "{count, plural, =1 {# día} other {# días}}", - "hours": "{count, plural, =1 {# hora} other {# horas}}", - "minutes": "{count, plural, =1 {# minuto} other {# minutos}}", - "seconds": "{count, plural, =1 {# segundo} other {# segundos}}" - } + "error": { + "generic": { + "title": "Error!", + "message": "Hubo un error desconocido. ¡Entra en pánico!" + }, + "invalid_url": { + "title": "Esto no está bien.", + "message": "Este URL no es válido. Intenta otro, ¿Tal vez?" + } + }, + "footer": { + "choose_language": "Escoge un lenguaje", + "license": "Forum es <a href=\"{licenseUrl}\">software libre.</a>", + "title": "Pie de página" + }, + "forum": { + "forum": "foro", + "name": { + "everything": "Todo", + "us": "Nosotros", + "words": "Palabras", + "sound": "Sonidos", + "structure": "Estructura", + "interaction": "Interacción", + "emotion": "Emoción", + "movement": "Movimiento", + "belief": "Creencia", + "experience": "Experiencia", + "online": "En Línea", + "the_world": "El Mundo", + "life": "Vida" + }, + "error": { + "unavailable": "Temas del foro no disponibles." + } + }, + "forum_list": { + "title": "Lista de foros", + "error": { + "unavailable": "Lista de foros no disponible." + } + }, + "glyph": { + "title": "Avatar del usuario" + }, + "header": { + "action": { + "new": { + "title": "Nuevo", + "display": "<u>N</u>uevo" + }, + "reply": { + "title": "Responder", + "display": "<u>R</u>esponder" + }, + "search": { + "title": "Buscar", + "display": "Bu<u>s</u>car" + }, + "log_out": { + "title": "Cerrar Sesión", + "display": "Cerrar Sesi<u>ó</u>n" + } + }, + "long_version": "Forum versión {version}", + "title": "Barra de herramientas", + "short_version": "Forum v{version}" + }, + "home": { + "title": "Hola.", + "content": "Ahora estás en un foro. Elige una categoría de la izquierda o escribe un URL válido." + }, + "loader": { + "message": "Cargando." + }, + "post": { + "author_credit": "Por:", + "metadata_title": "Metadatos de entrada {count} de {total}", + "permalink_title": "Permalink a entrada", + "post": "Entrada", + "title": "Entrada {count} de {total}, por {author}", + "topic_location": "En", + "error": { + "unavailable": "Entrada no disponible." + } + }, + "tag": { + "title": "Etiqueta", + "error": { + "unavailable": "Temas de la etiqueta no disponibles." + } + }, + "topic": { + "category_location": "Agregado a", + "metadata_title": "Metadatos del tema", + "permalink_title": "Permalink al tema", + "remaining_time": "Quedan {remaining}", + "tags_location": "Etiquetas:", + "tags_title": "Etiquetas del tema", + "title": "Tema", + "error": { + "unavailable": "Tema no disponible." + } + }, + "time": { + "days": "{count, plural, =1 {# día} other {# días}}", + "hours": "{count, plural, =1 {# hora} other {# horas}}", + "minutes": "{count, plural, =1 {# minuto} other {# minutos}}", + "seconds": "{count, plural, =1 {# segundo} other {# segundos}}" + } } diff --git a/src/data/queries.js b/src/data/queries.js index 93e4b23..7364c0f 100644 --- a/src/data/queries.js +++ b/src/data/queries.js @@ -1,90 +1,90 @@ import { gql } from '@apollo/client/core'; export const GET_FORUMS = gql` - query GetForums { - forums { - id - glyph - label - position - } - } + query GetForums { + forums { + id + glyph + label + position + } + } `; export const GET_FORUM = gql` - query GetForum($id: ID!) { - forum(id: $id) { - id - glyph - label - position - topics { - id - title - updated_at - ttl - } - } - } + query GetForum($id: ID!) { + forum(id: $id) { + id + glyph + label + position + topics { + id + title + updated_at + ttl + } + } + } `; export const GET_TAG = gql` - query GetTag($id: ID!) { - tag(id: $id) { - id - topics { - id - title - updated_at - ttl - } - } - } + query GetTag($id: ID!) { + tag(id: $id) { + id + topics { + id + title + updated_at + ttl + } + } + } `; export const GET_TOPIC = gql` - query GetTopic($id: ID!) { - topic(id: $id) { - id - title - updated_at - ttl - forum { - id - glyph - label - } - tags { - id - weight - } - posts { - id - text - created_at - author { - id - handle - } - } - } - } + query GetTopic($id: ID!) { + topic(id: $id) { + id + title + updated_at + ttl + forum { + id + glyph + label + } + tags { + id + weight + } + posts { + id + text + created_at + author { + id + handle + } + } + } + } `; export const GET_POST = gql` - query GetPost($id: ID!) { - post(id: $id) { - id - text - created_at - author { - id - handle - } - topic { - id - title - } - } - } + query GetPost($id: ID!) { + post(id: $id) { + id + text + created_at + author { + id + handle + } + topic { + id + title + } + } + } `; diff --git a/src/forum.js b/src/forum.js deleted file mode 100644 index 1e8ec25..0000000 --- a/src/forum.js +++ /dev/null @@ -1,6 +0,0 @@ -import HMR from '@roxi/routify/hmr'; -import Forum from './Forum.svelte'; - -const app = HMR(Forum, { target: document.body }, 'forum'); - -export default app; diff --git a/src/forum.svelte b/src/forum.svelte deleted file mode 100644 index 0eb4b90..0000000 --- a/src/forum.svelte +++ /dev/null @@ -1,6 +0,0 @@ -<script> - import { Router } from '@roxi/routify'; - import { routes } from '../.routify/routes'; -</script> - -<Router {routes} /> diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..79d7d7f --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,3 @@ +/// <reference types="@sveltejs/kit" /> +/// <reference types="svelte" /> +/// <reference types="vite/client" /> diff --git a/src/pages/_fallback.svelte b/src/pages/_fallback.svelte deleted file mode 100644 index 7c88129..0000000 --- a/src/pages/_fallback.svelte +++ /dev/null @@ -1,5 +0,0 @@ -<script> - import InvalidRoute from '$/components/invalid_route/invalid_route.svelte'; -</script> - -<InvalidRoute /> diff --git a/src/pages/_layout.svelte b/src/pages/_layout.svelte deleted file mode 100644 index b296b73..0000000 --- a/src/pages/_layout.svelte +++ /dev/null @@ -1,37 +0,0 @@ -<script> - import '$/config/i18n'; - import { isLoading } from 'svelte-i18n'; - import ForumList from '$/components/forum_list/forum_list.svelte'; - import Header from '$/components/header/header.svelte'; - import Loader from '$/components/loader/loader.svelte'; - import Footer from '$/components/footer/footer.svelte'; -</script> - -{#if $isLoading} - <Loader /> -{:else} - <Header /> - <main> - <slot></slot> - </main> - <ForumList /> - <Footer /> -{/if} - -<style> - main { - grid-column: col-start 2 / span 11; - } - - :global(#forum) { - display: grid; - font-family : 'ヒラギノ明朝 ProN' , 'Hiragino Mincho ProN' , '游明朝','游明朝体',YuMincho,'Yu Mincho' , 'MS 明朝' , 'MS Mincho' , HiraMinProN-W3 , 'TakaoEx明朝' , TakaoExMincho , 'MotoyaLCedar' , 'Droid Sans Japanese' , serif; - grid-template-columns: repeat(12, [col-start] 1fr); - grid-gap: 20px; - grid-auto-rows: minmax(24px, auto); - } - - :global(body) { - background-color: whitesmoke; - } -</style> diff --git a/src/pages/a/[id].svelte b/src/pages/a/[id].svelte deleted file mode 100644 index f9bd858..0000000 --- a/src/pages/a/[id].svelte +++ /dev/null @@ -1,5 +0,0 @@ -<script> - import Author from '$/components/author/author.svelte'; -</script> - -<Author/> diff --git a/src/pages/f/[id].svelte b/src/pages/f/[id].svelte deleted file mode 100644 index 473a58d..0000000 --- a/src/pages/f/[id].svelte +++ /dev/null @@ -1,6 +0,0 @@ -<script> - import Forum from '$/components/forum/forum.svelte'; - export let id; -</script> - -<Forum id={id}/> diff --git a/src/pages/g/[id].svelte b/src/pages/g/[id].svelte deleted file mode 100644 index 754f129..0000000 --- a/src/pages/g/[id].svelte +++ /dev/null @@ -1,6 +0,0 @@ -<script> - import Tag from '$/components/tag/tag.svelte'; - export let id; -</script> - -<Tag id={id}/> diff --git a/src/pages/index.svelte b/src/pages/index.svelte deleted file mode 100644 index b716772..0000000 --- a/src/pages/index.svelte +++ /dev/null @@ -1,8 +0,0 @@ -<script> - import { _ } from 'svelte-i18n'; - import Loader from '$/components/loader/loader.svelte'; -</script> - -<Loader /> -<h1>{$_('home.title')}</h1> -<p>{$_('home.content')}</p> diff --git a/src/pages/p/[id].svelte b/src/pages/p/[id].svelte deleted file mode 100644 index 3504cea..0000000 --- a/src/pages/p/[id].svelte +++ /dev/null @@ -1,6 +0,0 @@ -<script> - import Post from '$/components/post/post.svelte'; - export let id; -</script> - -<Post id={id}/> diff --git a/src/pages/t/[topic_id].svelte b/src/pages/t/[topic_id].svelte deleted file mode 100644 index 8ead8f3..0000000 --- a/src/pages/t/[topic_id].svelte +++ /dev/null @@ -1,6 +0,0 @@ -<script> - import Topic from '$/components/topic/topic.svelte'; - export let topic_id; -</script> - -<Topic id={topic_id}/> diff --git a/src/routes/$error.svelte b/src/routes/$error.svelte new file mode 100644 index 0000000..0dd2cf6 --- /dev/null +++ b/src/routes/$error.svelte @@ -0,0 +1,5 @@ +<script> + import InvalidRoute from '$/components/invalid_route/invalid_route.svelte'; +</script> + +<InvalidRoute /> diff --git a/src/routes/$layout.svelte b/src/routes/$layout.svelte new file mode 100644 index 0000000..49ceb49 --- /dev/null +++ b/src/routes/$layout.svelte @@ -0,0 +1,19 @@ +<script> + import '$/config/i18n'; + import { isLoading } from 'svelte-i18n'; + import ForumList from '$/components/forum_list/forum_list.svelte'; + import Header from '$/components/header/header.svelte'; + import Loader from '$/components/loader/loader.svelte'; + import Footer from '$/components/footer/footer.svelte'; +</script> + +{#if $isLoading} + <Loader /> +{:else} + <Header /> + <main> + <slot /> + </main> + <ForumList /> + <Footer /> +{/if} diff --git a/src/routes/a/[id].svelte b/src/routes/a/[id].svelte new file mode 100644 index 0000000..5f8c951 --- /dev/null +++ b/src/routes/a/[id].svelte @@ -0,0 +1,13 @@ +<script context="module"> + export const load = ({ + page: { + params: { id } + } + }) => ({ props: { id } }); +</script> + +<script> + import Author from '$/components/author/author.svelte'; +</script> + +<Author /> diff --git a/src/routes/f/[id].svelte b/src/routes/f/[id].svelte new file mode 100644 index 0000000..83afc8a --- /dev/null +++ b/src/routes/f/[id].svelte @@ -0,0 +1,34 @@ +<script context="module"> + export const load = ({ + page: { + params: { id } + } + }) => ({ props: { id } }); +</script> + +<script> + import { _ } from 'svelte-i18n'; + import Forum from '$/components/forum/forum.svelte'; + import ErrorBlock from '$/components/error_block/error_block.svelte'; + import Loader from '$/components/loader/loader.svelte'; + + export let id; + + import { getForum } from '$/stores/forum'; + $: store = getForum(id); + $: forum = $store.data; +</script> + +<svelte:head> + <title>{$_(`forum.name.${id}`)}, {$_('forum.forum')}</title> +</svelte:head> + +{#if $store.loading} + <Loader /> +{/if} +{#if $store.error} + <ErrorBlock message={$_('forum.error.unavailable')} /> +{/if} +{#if forum} + <Forum {forum} /> +{/if} diff --git a/src/routes/g/[id].svelte b/src/routes/g/[id].svelte new file mode 100644 index 0000000..023fbd8 --- /dev/null +++ b/src/routes/g/[id].svelte @@ -0,0 +1,33 @@ +<script context="module"> + export const load = ({ + page: { + params: { id } + } + }) => ({ props: { id } }); +</script> + +<script> + import { _ } from 'svelte-i18n'; + import { getTag } from '$/stores/tag'; + import ErrorBlock from '$/components/error_block/error_block.svelte'; + import Loader from '$/components/loader/loader.svelte'; + import Tag from '$/components/tag/tag.svelte'; + export let id; + + $: store = getTag(id); + $: tag = $store.data; +</script> + +<svelte:head> + <title>{id}, {$_('tag.title')}</title> +</svelte:head> + +{#if $store.loading} + <Loader /> +{/if} +{#if $store.error} + <ErrorBlock message={$_('tag.error.unavailable')} /> +{/if} +{#if tag} + <Tag {tag} /> +{/if} diff --git a/src/routes/index.svelte b/src/routes/index.svelte new file mode 100644 index 0000000..687d8f3 --- /dev/null +++ b/src/routes/index.svelte @@ -0,0 +1,12 @@ +<script> + import { _ } from 'svelte-i18n'; + import Loader from '$/components/loader/loader.svelte'; +</script> + +<svelte:head> + <title>Forum.</title> +</svelte:head> + +<Loader /> +<h1>{$_('home.title')}</h1> +<p>{$_('home.content')}</p> diff --git a/src/routes/p/[id].svelte b/src/routes/p/[id].svelte new file mode 100644 index 0000000..915cfeb --- /dev/null +++ b/src/routes/p/[id].svelte @@ -0,0 +1,34 @@ +<script context="module"> + export const load = ({ + page: { + params: { id } + } + }) => ({ props: { id } }); +</script> + +<script> + import { _ } from 'svelte-i18n'; + import { getPost } from '$/stores/post'; + import Post from '$/components/post/post.svelte'; + import ErrorBlock from '$/components/error_block/error_block.svelte'; + import Loader from '$/components/loader/loader.svelte'; + + export let id; + + $: store = getPost(id); + $: post = $store.data; +</script> + +<svelte:head> + <title>{$_('post.post')}}</title> +</svelte:head> + +{#if $store.loading} + <Loader /> +{/if} +{#if $store.error} + <ErrorBlock message={$_('post.error.unavailable')} /> +{/if} +{#if post} + <Post {post} /> +{/if} diff --git a/src/routes/t/[id].svelte b/src/routes/t/[id].svelte new file mode 100644 index 0000000..9d3ab9e --- /dev/null +++ b/src/routes/t/[id].svelte @@ -0,0 +1,48 @@ +<script context="module"> + export const load = ({ + page: { + params: { id } + } + }) => ({ props: { id } }); +</script> + +<script> + import { onDestroy } from 'svelte'; + import { _ } from 'svelte-i18n'; + import { getTopic } from '$/stores/topic'; + import { disableTopicActions, enableTopicActions } from '$/stores/actions'; + + import Topic from '$/components/topic/topic.svelte'; + import ErrorBlock from '$/components/error_block/error_block.svelte'; + import Loader from '$/components/loader/loader.svelte'; + + export let id; + + $: store = getTopic(id); + $: topic = $store.data; + + enableTopicActions(id); + onDestroy(() => disableTopicActions()); +</script> + +<svelte:head> + {#if $store.loading} + <title>{$_('loader.message')}, {$_('topic.title')}</title> + {/if} + {#if $store.error} + <title>{$_('error.generic.title')}, {$_('topic.title')}</title> + {/if} + {#if topic} + <title>{topic.title}, {$_('topic.title')}</title> + {/if} +</svelte:head> + +{#if $store.loading} + <Loader /> +{/if} +{#if $store.error} + <ErrorBlock message={$_('topic.error.unavailable')} /> +{/if} +{#if topic} + <Topic {topic} /> +{/if} diff --git a/src/socket_coordinator.js b/src/socket_coordinator.js deleted file mode 100644 index f8fb525..0000000 --- a/src/socket_coordinator.js +++ /dev/null @@ -1,63 +0,0 @@ -import EventEmitter from 'eventemitter3'; -import { socketServer } from './config/config'; - -const internals = { - - kReconnectInterval: 3000, // How often we attempt to reconnect - - eventEmitter: new EventEmitter(), // internal event emitter - socket: null, // stores the socket connection - retry: null, // stores the retry operation - - connect() { - - console.debug('Connecting socket.'); - internals.socket = new WebSocket(socketServer); - - internals.socket.addEventListener('message', internals.onMessage); - internals.socket.addEventListener('error', internals.onError); - internals.socket.addEventListener('close', internals.onClose); - }, - - // Handles socket errors. - - onError(event) { - - console.error('Socket error. Closing connection'); - internals.socket.close(); - }, - - // Handles socket errors. - - onClose(event) { - - console.debug(`Connection closed: ${event.reason || 'Unknown reason'}. Retrying in ${internals.kReconnectInterval}ms`); - - internals.retry && clearTimeout(internals.retry); - internals.retry = setTimeout(() => { - - console.debug('Reconnecting socket.'); - internals.retry = null; - internals.connect(); - }, internals.kReconnectInterval); - }, - - // Forwards events from the socket to our internal event emitter. - - onMessage(event) { - - internals.eventEmitter.emit('message', event); - } -}; - -export const onMessage = function (listener) { - - if (!internals.socket) { - internals.connect(); - } - - internals.eventEmitter.on('message', (message) => { - - listener(JSON.parse(message.data)); - }); -}; diff --git a/src/stores/actions.js b/src/stores/actions.js new file mode 100644 index 0000000..3a6d13f --- /dev/null +++ b/src/stores/actions.js @@ -0,0 +1,25 @@ +import { writable } from 'svelte/store'; + +/* + * This is a store to set the actions in the top header. + */ + +export const actions = writable({}); + +export const enableTopicActions = (id) => { + + actions.update((actionsValue) => { + + actionsValue.topic_id = id; + return actionsValue; + }); +}; + +export const disableTopicActions = () => { + + actions.update((actionsValue) => { + + delete actionsValue.id; + return actionsValue; + }); +}; diff --git a/src/stores/apollo.js b/src/stores/apollo.js index 0ac2443..f84a183 100644 --- a/src/stores/apollo.js +++ b/src/stores/apollo.js @@ -8,33 +8,39 @@ import { client } from '$/config/apollo'; export const store = function store({ key, query, initialValue = null, variables = {} }) { - return readable({ - loading: true, - data: initialValue, - error: undefined - }, (set) => { + return readable( + { + loading: true, + data: initialValue, + error: undefined + }, + (set) => { - const handleError = function (error) { + const handleError = function (error) { - return set({ - loading: false, - data: initialValue, - error - }); - }; + return set({ + loading: false, + data: initialValue, + error + }); + }; - client.watchQuery({ query, variables }).subscribe((result) => { + client.watchQuery({ query, variables }).subscribe( + (result) => { - if (result.errors) { - const error = new ApolloError({ graphQLErrors: result.errors }); - return handleError(error); - } + if (result.errors) { + const error = new ApolloError({ graphQLErrors: result.errors }); + return handleError(error); + } - set({ - loading: false, - data: result.data[key], - error: undefined - }); - }, (error) => handleError(error)); - }); + set({ + loading: false, + data: result.data[key], + error: undefined + }); + }, + (error) => handleError(error) + ); + } + ); }; diff --git a/src/utils/glyph_hash.js b/src/utils/glyph_hash.js index cbbf988..13a81a8 100644 --- a/src/utils/glyph_hash.js +++ b/src/utils/glyph_hash.js @@ -1,38 +1,21 @@ const internals = { kSplitterRegex: /.{1,8}/g, - kGlyphs: [ - '☽', - '☆', - '♢', - '♡', - '╱', - '╲', - '╳', - '〰', - '▷', - '⏊', - '〒', - '▢', - '◯', - '⏃', - '⏀', - '⏆' - ] + kGlyphs: ['☽', '☆', '♢', '♡', '╱', '╲', '╳', '〰', '▷', '⏊', '〒', '▢', '◯', '⏃', '⏀', '⏆'] }; // Return a glyph with color based on a 4 byte fragment of a UUIDv4 const getGlyphHashFragment = function (uuidFragment) { - const glyphIndex = parseInt(uuidFragment.substring(0,2), 16) % 16; + const glyphIndex = parseInt(uuidFragment.substring(0, 2), 16) % 16; return { glyph: internals.kGlyphs[glyphIndex], - color: `#${uuidFragment.substring(2,8)}` + color: `#${uuidFragment.substring(2, 8)}` }; }; // Return an array of glyphs based on a UUIDv4 export const getGlyphHash = function (uuid) { - const hashFragments = uuid.replace(/[-]/g,'').match(internals.kSplitterRegex); + const hashFragments = uuid.replace(/[-]/g, '').match(internals.kSplitterRegex); return hashFragments.map(getGlyphHashFragment); }; |