]> git.r.bdr.sh - rbdr/forum/commitdiff
Port to sveltekit
authorRuben Beltran del Rio <redacted>
Thu, 15 Apr 2021 21:06:26 +0000 (23:06 +0200)
committerRuben Beltran del Rio <redacted>
Thu, 15 Apr 2021 21:06:26 +0000 (23:06 +0200)
48 files changed:
.eslintrc.cjs [new file with mode: 0644]
.npmrc [new file with mode: 0644]
src/animations/blink.js
src/app.css [new file with mode: 0644]
src/app.html [new file with mode: 0644]
src/components/error_block/error_block.svelte
src/components/footer/footer.svelte
src/components/forum/forum.svelte
src/components/forum_list/forum_list.svelte
src/components/glyph/glyph.svelte
src/components/header/header.svelte
src/components/home/home.svelte
src/components/invalid_route/invalid_route.svelte
src/components/language_selector/language_selector.svelte
src/components/loader/loader.svelte
src/components/post/post.svelte
src/components/post_content/post_content.svelte
src/components/tag/tag.svelte
src/components/topic/topic.svelte
src/components/topic_summary/topic_summary.svelte
src/config/apollo.js
src/config/config.js
src/config/translations/en.json
src/config/translations/es.json
src/data/queries.js
src/forum.js [deleted file]
src/forum.svelte [deleted file]
src/global.d.ts [new file with mode: 0644]
src/pages/_fallback.svelte [deleted file]
src/pages/_layout.svelte [deleted file]
src/pages/a/[id].svelte [deleted file]
src/pages/f/[id].svelte [deleted file]
src/pages/g/[id].svelte [deleted file]
src/pages/index.svelte [deleted file]
src/pages/p/[id].svelte [deleted file]
src/pages/t/[topic_id].svelte [deleted file]
src/routes/$error.svelte [new file with mode: 0644]
src/routes/$layout.svelte [new file with mode: 0644]
src/routes/a/[id].svelte [new file with mode: 0644]
src/routes/f/[id].svelte [new file with mode: 0644]
src/routes/g/[id].svelte [new file with mode: 0644]
src/routes/index.svelte [new file with mode: 0644]
src/routes/p/[id].svelte [new file with mode: 0644]
src/routes/t/[id].svelte [new file with mode: 0644]
src/socket_coordinator.js [deleted file]
src/stores/actions.js [new file with mode: 0644]
src/stores/apollo.js
src/utils/glyph_hash.js

diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644 (file)
index 0000000..55df7f3
--- /dev/null
@@ -0,0 +1,20 @@
+module.exports = {
+  root: true,
+  extends: ['@hapi/eslint-config-hapi'],
+  plugins: ['svelte3'],
+  overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
+  parserOptions: {
+    sourceType: 'module',
+    ecmaVersion: 2019
+  },
+  env: {
+    browser: true,
+    es2017: true,
+    node: true
+  },
+  rules: {
+    indent: [2, 2],
+    'no-undef': 2,
+    'require-yield': 0
+  }
+};
diff --git a/.npmrc b/.npmrc
new file mode 100644 (file)
index 0000000..b6f27f1
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+engine-strict=true
index eeed3deab3b971a80a12e86b84d09aaf84d35a9d..5515bb62d112153f4bb2a35b6ca591d0627ca9e9 100644 (file)
@@ -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 (file)
index 0000000..1d7e288
--- /dev/null
@@ -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 (file)
index 0000000..062ed0f
--- /dev/null
@@ -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>
index b85a2ea196af579dc4dae373badf0c063dda5544..3a43a1ead80a78238d3f9a9d02d07b9556ae3243 100644 (file)
@@ -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>
-
index 317319e052f3821835ea66c20ad207354d4e2c16..2d5f8ff1050d5b02d68cbe2131f9f0f358a07e08 100644 (file)
@@ -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>
index 8fc0538327f91a241b6481aa1233602c38a07b58..ea9b2064e5ea8e73cd28c7054143a7eaa6b7192b 100644 (file)
@@ -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>
index 2998c09c22136c100c01e9010d0bb6fda34d3e6a..7bfb7b238148d66e718b71773de189680302cfcf 100644 (file)
@@ -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>
index 32e8ee65cf3e5c8e01bfc1f24793485caeba6847..e430d428bc39e9d78888ab2f522f4c303d45b354 100644 (file)
@@ -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>
index c68a685f6c5226397433376031c23f7afa862427..f33e77bf445cdb38fb17176f3a259e8f6031088e 100644 (file)
@@ -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>
index 7000137e92680cc33cf695cc41cba28912d95acc..fa4a70e17b8d6a01b8f9b73da1aa79bb0761c906 100644 (file)
@@ -1,5 +1,5 @@
 <script>
-  import { _ } from 'svelte-i18n';
+       import { _ } from 'svelte-i18n';
 </script>
 
 <h1>{$_('home.title')}</h1>
index aaf7927a71de0f80f9a9d4909d3c4234973ca9f4..2a3686c172df0f0ed267d0b66f31666ba9bdf8d4 100644 (file)
@@ -1,5 +1,5 @@
 <script>
-  import { _ } from 'svelte-i18n';
+       import { _ } from 'svelte-i18n';
 </script>
 
 <h1>{$_('error.invalid_url.title')}</h1>
index 3ac4894008088e0015d2234fbeccfc3bedae03df..3338810ca48a419b9d0a46d0d97ac2fc86c883d2 100644 (file)
@@ -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>
-
index e9787aa57b7e17e9e8237af20877d2785b519c35..8d5373620c270e5c152e0e1182556132d751e2da 100644 (file)
@@ -1,5 +1,5 @@
 <script>
-  import { _ } from 'svelte-i18n';
+       import { _ } from 'svelte-i18n';
 </script>
 
 <p>{$_('loader.message')}</p>
index bf2a190a554695d289b6d3ebdac5856cf998dde1..5d8ef1cb179d1e1bdf6cc033b1078ec7d6c949fb 100644 (file)
@@ -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>
index 671c07c02b7dc180329eda07ef459070646f0b3d..5d8ef1cb179d1e1bdf6cc033b1078ec7d6c949fb 100644 (file)
@@ -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>
index a14cd19103e3acf23361549d2f2b3fca3fc62bdd..954cdaa7464086826f38f07e6bb716a704f8d2e5 100644 (file)
@@ -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>
index 9be7346b76f39088166107c5c18728670259e217..181b429557fde68a23a9cdc9ad185dcfc03e83c1 100644 (file)
@@ -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>
index 88b2b83232dcae2fed43f8539c97c406692bd462..5f2678b7d711a6ea5495966e821991133ded9b0c 100644 (file)
@@ -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>
index 4cfca79ba4b6eefd9b9f8b42f251cd3392a78d0c..a3820ed70355cc24a896c55e759874601c019865 100644 (file)
@@ -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
 });
index 0570e1cd312e85a22022daea96fc023a1a2ce694..9d6d40edb1646341bf2c29efdbda1030bf2f6f57 100644 (file)
@@ -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;
index cf66bf214f263b1ee75bab1271c4cd5739972cb3..14e89e47e08969f1eed3cb7033815b57c0f645dc 100644 (file)
 {
-  "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}}"
+       }
 }
index 6b6880f49c49536725bb96528f9313bbe60e8fe9..4f6b0c1c3b01486e2a8c262a1a0f9bf460419aa9 100644 (file)
 {
-  "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}}"
+       }
 }
index 93e4b233575e440b2d1ed40cb10f1449d00d2e46..7364c0f1dd7e0095d24b4f4cf47e7bb8c64e2287 100644 (file)
@@ -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 (file)
index 1e8ec25..0000000
+++ /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 (file)
index 0eb4b90..0000000
+++ /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 (file)
index 0000000..79d7d7f
--- /dev/null
@@ -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 (file)
index 7c88129..0000000
+++ /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 (file)
index b296b73..0000000
+++ /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 (file)
index f9bd858..0000000
+++ /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 (file)
index 473a58d..0000000
+++ /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 (file)
index 754f129..0000000
+++ /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 (file)
index b716772..0000000
+++ /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 (file)
index 3504cea..0000000
+++ /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 (file)
index 8ead8f3..0000000
+++ /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 (file)
index 0000000..0dd2cf6
--- /dev/null
@@ -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 (file)
index 0000000..49ceb49
--- /dev/null
@@ -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 (file)
index 0000000..5f8c951
--- /dev/null
@@ -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 (file)
index 0000000..83afc8a
--- /dev/null
@@ -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 (file)
index 0000000..023fbd8
--- /dev/null
@@ -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 (file)
index 0000000..687d8f3
--- /dev/null
@@ -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 (file)
index 0000000..915cfeb
--- /dev/null
@@ -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 (file)
index 0000000..9d3ab9e
--- /dev/null
@@ -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 (file)
index f8fb525..0000000
+++ /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 (file)
index 0000000..3a6d13f
--- /dev/null
@@ -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;
+  });
+};
index 0ac244353c12a4ac6b6d25207a03bb38d13ad48a..f84a183f4060cb4741d6fc745526cc6bc45bd1cf 100644 (file)
@@ -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) => {
-
-    const handleError = function (error) {
-
-      return set({
-        loading: false,
-        data: initialValue,
-        error
-      });
-    };
-
-    client.watchQuery({ query, variables }).subscribe((result) => {
-
-      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));
-  });
+  return readable(
+    {
+      loading: true,
+      data: initialValue,
+      error: undefined
+    },
+    (set) => {
+
+      const handleError = function (error) {
+
+        return set({
+          loading: false,
+          data: initialValue,
+          error
+        });
+      };
+
+      client.watchQuery({ query, variables }).subscribe(
+        (result) => {
+
+          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)
+      );
+    }
+  );
 };
index cbbf9883ea65ba262cf9abbeb7726660dedbd0d8..13a81a8286af15555a980be11ce54ce39661ef66 100644 (file)
@@ -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);
 };