on main help sign in
docs!
e2db5b5John Hyde
ui/src/App.svelte+4−2
@@ -1,13 +1,14 @@
1<script lang="ts">
1<script lang="ts">
2 import Router from 'svelte-spa-router';
2 import Router from 'svelte-spa-router';
3− import Urbit from '@urbit/http-api';
4− import { Charges, ChargeUpdateInitial, scryCharges } from '@urbit/api';
5 import Home from './routes/Home.svelte';
3 import Home from './routes/Home.svelte';
4+ import HelpPage from './routes/HelpPage.svelte';
6 import ShipViewPage from './routes/ShipViewPage.svelte';
5 import ShipViewPage from './routes/ShipViewPage.svelte';
6+ import HelpModal from './components/HelpModal.svelte';
7 import "./styles/styles.scss";
7 import "./styles/styles.scss";
8
8
9 const routes = {
9 const routes = {
10 // '/': Home,
10 // '/': Home,
11+ '/help/:path?': HelpPage,
11 '/:patp?': ShipViewPage,
12 '/:patp?': ShipViewPage,
12 '/ship/:patp?': ShipViewPage,
13 '/ship/:patp?': ShipViewPage,
13 '*': Home,
14 '*': Home,
@@ -15,5 +16,6 @@
15</script>
16</script>
16
17
17<main>
18<main>
19+ <HelpModal />
18 <Router {routes} />
20 <Router {routes} />
19</main>
21</main>
ui/src/actions/doc.tsdeleted−39
@@ -1,39 +0,0 @@
1−import UrbitApi from '@urbit/http-api';
2−const api: UrbitApi = new UrbitApi('');
3−
4−async function getDoc(path) {
5− return api.scry<any>({ app: 'astrolabe', path: `/doc/${path}` });
6−}
7−
8−export default function doc(node, path: string) {
9− // Determine the title to show. We want to prefer
10− // the custom content passed in first, then the
11− // HTML title attribute then the aria-label
12− // in that order.
13− const custom = params.content;
14− const title = node.title;
15− const label = node.getAttribute("aria-label");
16− const content = custom || title || label;
17−
18− // Let's make sure the "aria-label" attribute
19− // is set so our element is accessible:
20− // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute
21− if (!label) node.setAttribute("aria-label", content);
22−
23− // Clear out the HTML title attribute since
24− // we don't want the default behavior of it
25− // showing up on hover.
26− node.title = "";
27−
28− // Support any of the Tippy props by forwarding all "params":
29− // https://atomiks.github.io/tippyjs/v6/all-props/
30− const tip: any = tippy(node, mergeParams(content, params));
31−
32− return {
33− // If the props change, let's update the Tippy instance:
34− update: (newParams) => tip.setProps(mergeParams(content, newParams)),
35−
36− // Clean up the Tippy instance on unmount:
37− destroy: () => tip.destroy(),
38− };
39−};
ui/src/actions/docLinks.tsnew file+27
@@ -0,0 +1,27 @@
1+const docLinkRegex = /\/~\/scry\/docs\/usr\/astrolabe\/([-~._\w\d]+).html/;
2+
3+function convertDocLinks(node, onPathChange) {
4+ console.log(node);
5+ const links = node.querySelectorAll('a');
6+ for (let link of links) {
7+ let match = link.href.match(docLinkRegex);
8+ if (match) {
9+ let path = match[1];
10+ link.href="javascript:void(0)";
11+ link.addEventListener('click', () => onPathChange(path));
12+ // const button = document.createElement('button');
13+ // while(link.firstChild) {
14+ // button.appendChild(link.firstChild);
15+ // }
16+ // link.parentNode.replaceChild(button, link);
17+ // debugger;
18+ }
19+ }
20+}
21+
22+export default function docLinks(node, onPathChange: Function) {
23+ convertDocLinks(node, onPathChange)
24+ return {
25+ update: (onPathChange) => convertDocLinks(node, onPathChange),
26+ };
27+};
ui/src/components/Doc.svelte+24−12
@@ -1,17 +1,29 @@
1<script lang="ts">
1<script lang="ts">
2− import store from '../stores/store';
2+ import { createEventDispatcher } from 'svelte';
3+ import DocContent from './DocContent.svelte';
4+ import Hamburger from './buttons/Hamburger.svelte';
5+
6+ export let path: string;
7+
8+ const dispatch = createEventDispatcher();
9+ function close() {
10+ dispatch('close');
11+ }
3
12
4− export let path:string;
13+ function navigate(path) {
14+ dispatch('navigate', path);
15+ }
5</script>
16</script>
6
17
7−<div class="doc">
18+<div class="p-8 rounded-lg bg-white">
8− {#await store.getDoc(path)}
19+ <div class="flex">
9− <h3>Loading page...</h3>
20+ <Hamburger />
10− {:then docHtml}
21+ <div class="flex-grow text-center text-xl">
11− {@html docHtml}
22+ Help
12− {:catch error}
23+ </div>
13− <h1>Oops!</h1>
24+ <button class="w-10" on:click={close}>
14− <h2>Couldn't load the doc at /{path}</h2>
25+ X
15− <p>Please DM ~midlev-mindyr so he can fix this.</p>
26+ </button>
16− {/await}
27+ </div>
28+ <DocContent {path} on:navigate />
17</div>
29</div>
ui/src/components/DocContent.sveltenew file+35
@@ -0,0 +1,35 @@
1+<script lang="ts">
2+
3+ import { createEventDispatcher } from 'svelte';
4+
5+ import docLinks from "../actions/docLinks";
6+ import docs from "../stores/docs";
7+
8+ export let path:string;
9+
10+ const dispatch = createEventDispatcher();
11+ function navigate(path) {
12+ dispatch('navigate', path);
13+ }
14+
15+ function convertLinks(html: string): string {
16+ let converted = html;
17+ const externalLinkRegex = /href="http/g;
18+ converted = converted.replace(externalLinkRegex, 'target="_blank" href="http');
19+ return converted;
20+ }
21+</script>
22+
23+<div class="doc">
24+ {#await docs.getDoc(path)}
25+ <h3>Loading page...</h3>
26+ {:then docHtml}
27+ <div use:docLinks={navigate}>
28+ {@html convertLinks(docHtml)}
29+ </div>
30+ {:catch error}
31+ <h1>Oops!</h1>
32+ <h2>Couldn't load the doc at /{path}</h2>
33+ <p>Please DM ~midlev-mindyr so he can fix this.</p>
34+ {/await}
35+</div>
ui/src/components/DocModal.sveltedeleted−9
@@ -1,9 +0,0 @@
1−<script lang="ts">
2− import Doc from './Doc.svelte';
3−
4− export let path:string;
5−</script>
6−
7−<div class="p-8 rounded-lg bg-white">
8− <Doc {path} />
9−</div>
ui/src/components/GlobalDocModal.sveltedeleted−6
@@ -1,6 +0,0 @@
1−<script lang="ts">
2− import appState from '../stores/appState';
3− import DocModal from '../components/DocModal.svelte';
4−</script>
5−
6−<DocModal modal showModal={$appState.showDoc} path={$appState.path} />
ui/src/components/HelpModal.sveltenew file+11
@@ -0,0 +1,11 @@
1+<script lang="ts">
2+ import docs from '../stores/docs';
3+ import Doc from './Doc.svelte';
4+
5+ // $: title = path ? capitalizeWords(path.replace(/-/g, ' ')) : 'Help';
6+
7+</script>
8+
9+{#if $docs.show}
10+<Doc path={$docs.path} on:close={() => docs.hide()} on:navigate={(event) => docs.show(event.detail)} />
11+{/if}
ui/src/components/buttons/Hamburger.sveltenew file+5
@@ -0,0 +1,5 @@
1+<div class="w-10 space-y-2">
2+ <div class="h-2 w-full bg-navy rounded" />
3+ <div class="h-2 w-full bg-navy rounded" />
4+ <div class="h-2 w-full bg-navy rounded" />
5+</div>
ui/src/routes/HelpPage.svelte+10−2
@@ -1,10 +1,18 @@
1<script lang="ts">
1<script lang="ts">
2+ import { push } from 'svelte-spa-router';
2− import DocModal from '../components/DocModal.svelte';
3+ import Doc from '../components/Doc.svelte';
3 export let params: any = {};
4 export let params: any = {};
4 $: path = params.path || '';
5 $: path = params.path || '';
5
6
6 // $: title = path ? capitalizeWords(path.replace(/-/g, ' ')) : 'Help';
7 // $: title = path ? capitalizeWords(path.replace(/-/g, ' ')) : 'Help';
7
8
9+ function closeDoc() {
10+ push('#/');
11+ }
12+
13+ function navigate(event) {
14+ push(`#/help/${event.detail}`)
15+ }
8</script>
16</script>
9
17
10−<DocModal {path} />
18+<Doc {path} on:close={closeDoc} on:navigate={navigate} />
ui/src/routes/ShipViewPage.svelte+3−2
@@ -1,11 +1,12 @@
1<script lang="ts">
1<script lang="ts">
2 import { link, replace } from 'svelte-spa-router'
2 import { link, replace } from 'svelte-spa-router'
3+ import docs from '../stores/docs';
3 import { SearchAnalysis } from '../lib/id';
4 import { SearchAnalysis } from '../lib/id';
4 import { linkToShip } from '../lib/link';
5 import { linkToShip } from '../lib/link';
5 import SearchBar from "../components/SearchBar.svelte";
6 import SearchBar from "../components/SearchBar.svelte";
6 import ShipView from '../components/ShipView.svelte';
7 import ShipView from '../components/ShipView.svelte';
7 import ValidationProblems from '../components/ValidationProblems.svelte';
8 import ValidationProblems from '../components/ValidationProblems.svelte';
8− import DocModal from '../components/DocModal.svelte';
9+ import DocModal from '../components/Doc.svelte';
9 export let params: any = {};
10 export let params: any = {};
10 let patp: string;
11 let patp: string;
11 let analysis: SearchAnalysis = new SearchAnalysis();
12 let analysis: SearchAnalysis = new SearchAnalysis();
@@ -35,10 +36,10 @@
35 <!-- <a use:link={"/"} class="p-4 bg-white rounded-lg text-center">Go Home</a> -->
36 <!-- <a use:link={"/"} class="p-4 bg-white rounded-lg text-center">Go Home</a> -->
36 <!-- <SearchBar bind:searchText={search} bind:analysis /> -->
37 <!-- <SearchBar bind:searchText={search} bind:analysis /> -->
37 <SearchBar bind:analysis bind:search />
38 <SearchBar bind:analysis bind:search />
39+ <button on:click={() => docs.show('urbit-id')}>docs</button>
38 {#if analysis.patpIsValid}
40 {#if analysis.patpIsValid}
39 <ShipView patp={analysis.patp} />
41 <ShipView patp={analysis.patp} />
40 {:else if (search.length > 0)}
42 {:else if (search.length > 0)}
41 <ValidationProblems problems={analysis.patpProblems} />
43 <ValidationProblems problems={analysis.patpProblems} />
42 {/if}
44 {/if}
43− <DocModal path="test" />
44</div>
45</div>
ui/src/stores/appState.ts → ui/src/stores/docs.tsrenamed+11−4
@@ -5,7 +5,7 @@ const docs = {};
5// import type { AppState, Contacts } from '../types/store';
5// import type { AppState, Contacts } from '../types/store';
6
6
7const initStore: any = {
7const initStore: any = {
8− showDoc: false,
8+ show: false,
9 path: '',
9 path: '',
10};
10};
11
11
@@ -22,13 +22,20 @@ async function getDoc(path): Promise<string> {
22 }
22 }
23}
23}
24
24
25−async function showDoc(path) {
25+function show(path) {
26 update($store => ({
26 update($store => ({
27 ...$store,
27 ...$store,
28 path,
28 path,
29− showDoc: true,
29+ show: true,
30+ }));
31+}
32+
33+function hide() {
34+ update($store => ({
35+ ...$store,
36+ show: false,
30 }));
37 }));
31}
38}
32
39
33
40
34−export default { subscribe, getDoc, showDoc };
41+export default { subscribe, getDoc, show, hide };
ui/src/styles/tailwind-output.css+9−6
@@ -528,12 +528,15 @@ Ensure the default browser behavior of the `hidden` attribute.
528.h-12 {
528.h-12 {
529 height: 3rem;
529 height: 3rem;
530}
530}
531−.w-full {
531+.h-2 {
532− width: 100%;
532+ height: 0.5rem;
533}
533}
534.w-10 {
534.w-10 {
535 width: 2.5rem;
535 width: 2.5rem;
536}
536}
537+.w-full {
538+ width: 100%;
539+}
537.w-12 {
540.w-12 {
538 width: 3rem;
541 width: 3rem;
539}
542}
@@ -781,6 +784,10 @@ Ensure the default browser behavior of the `hidden` attribute.
781.font-mono {
784.font-mono {
782 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
785 font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
783}
786}
787+.text-xl {
788+ font-size: 1.25rem;
789+ line-height: 1.75rem;
790+}
784.text-3xl {
791.text-3xl {
785 font-size: 1.875rem;
792 font-size: 1.875rem;
786 line-height: 2.25rem;
793 line-height: 2.25rem;
@@ -797,10 +804,6 @@ Ensure the default browser behavior of the `hidden` attribute.
797 font-size: 0.875rem;
804 font-size: 0.875rem;
798 line-height: 1.25rem;
805 line-height: 1.25rem;
799}
806}
800−.text-xl {
801− font-size: 1.25rem;
802− line-height: 1.75rem;
803−}
804.text-base {
807.text-base {
805 font-size: 1rem;
808 font-size: 1rem;
806 line-height: 1.5rem;
809 line-height: 1.5rem;