on main help sign in
v0.3.4 update docs and rework sigil input modes
363cd2bJohn Hyde
.vscode/settings.json+6
@@ -48,5 +48,11 @@
48 }
48 }
49 ]
49 ]
50 }
50 }
51+ ],
52+ "grammarly.selectors": [
53+ {
54+ "language": "markdown",
55+ "scheme": "file"
56+ }
51 ]
57 ]
52}
58}
.vscode/tasks.json+3−3
@@ -3,11 +3,11 @@
3 "tasks": [
3 "tasks": [
4 {
4 {
5 "type": "npm",
5 "type": "npm",
6− "script": "commit",
6+ "script": "install:desk",
7 "path": "ui",
7 "path": "ui",
8 "problemMatcher": [],
8 "problemMatcher": [],
9− "label": "npm: commit - ui",
9+ "label": "npm: install:desk - ui",
10− "detail": "dotenv -c local npm run _commit"
10+ "detail": "dotenv -c local npm run _install:desk"
11 }
11 }
12 ]
12 ]
13}
13}
desk/desk.docket-0+2−2
@@ -2,9 +2,9 @@
2 info+'Your guide to the Urbit constellations'
2 info+'Your guide to the Urbit constellations'
3 color+0x1f.243c
3 color+0x1f.243c
4 image+'https://raw.githubusercontent.com/johnhyde/astrolabe/main/ui/src/assets/astrolabe-tile.svg'
4 image+'https://raw.githubusercontent.com/johnhyde/astrolabe/main/ui/src/assets/astrolabe-tile.svg'
5− glob-http+['https://s3.us-east-2.amazonaws.com/warkgnall.com/urbit/astrolabe/globs/glob-0v7.6404d.39fgn.ms148.c6qf4.9c0f3.glob' 0v7.6404d.39fgn.ms148.c6qf4.9c0f3]
5+ glob-http+['https://s3.us-east-2.amazonaws.com/warkgnall.com/urbit/astrolabe/globs/glob-0v2.jtc81.6iedn.re59t.n1mo1.9e0k8.glob' 0v2.jtc81.6iedn.re59t.n1mo1.9e0k8]
6 base+'astrolabe'
6 base+'astrolabe'
7− version+[0 3 3]
7+ version+[0 3 4]
8 website+'https://github.com/johnhyde/astrolabe'
8 website+'https://github.com/johnhyde/astrolabe'
9 license+'MIT'
9 license+'MIT'
10==
10==
desk/doc.toc+2−1
@@ -1,4 +1,4 @@
1−/overview/udon About Astrolabe
1+/overview/udon Overview
2/usr User
2/usr User
3 /urbit-id/udon What is an Urbit ID?
3 /urbit-id/udon What is an Urbit ID?
4 /galaxy/udon Galaxies
4 /galaxy/udon Galaxies
@@ -12,3 +12,4 @@
12 /azimuth/udon What is Azimuth?
12 /azimuth/udon What is Azimuth?
13 /l2/udon Layer 1 and Layer 2
13 /l2/udon Layer 1 and Layer 2
14 /keys/udon Networking Keys
14 /keys/udon Networking Keys
15+ /astrolabe/udon About Astrolabe
desk/doc/overview.udon+2
@@ -5,6 +5,8 @@ Currently Astrolabe lets you input `@p`s, Azimuth point numbers, or sigils
5to look up ships on the network. Use the Star Chart to explore visually.
5to look up ships on the network. Use the Star Chart to explore visually.
6There's also Help Documentation if you want to learn more about how Urbit IDs work.
6There's also Help Documentation if you want to learn more about how Urbit IDs work.
7
7
8+[How to Use Astrolabe](/~/scry/docs/usr/astrolabe/astrolabe.html)
9+
8## Info
10## Info
9
11
10- Developer: ~midlev-mindyr
12- Developer: ~midlev-mindyr
desk/doc/usr/astrolabe.udon+6−6
@@ -32,7 +32,7 @@ Clicking the symbol at the right of the search bar opens the Sigil Input Tool.
32Use the dropdown at the top to select Galaxy, Star, or Planet.
32Use the dropdown at the top to select Galaxy, Star, or Planet.
33Click on a square to start selecting sigil components.
33Click on a square to start selecting sigil components.
34
34
35−Select component catogeries on the right, and then tap the options on the sigil
35+Select component categories on the right, and then click the options on the sigil
36to add them to your search.
36to add them to your search.
37
37
38The ^ button goes up a level so you can select another category.
38The ^ button goes up a level so you can select another category.
@@ -40,13 +40,13 @@ The X button will clear sigil components from the current symbol,
40except the basic shape. If only the basic shape remains, the X button will clear that.
40except the basic shape. If only the basic shape remains, the X button will clear that.
41At the top level, the X button will clear all inputs.
41At the top level, the X button will clear all inputs.
42
42
43−Your contacts will be searched for any search.
43+Your contacts will be searched for any input.
44When the search has become specific enough,
44When the search has become specific enough,
45all spawned ships with matching sigils will be shown.
45all spawned ships with matching sigils will be shown.
46If your input is unambiguous, the page for the matching ship will be shown,
46If your input is unambiguous, the page for the matching ship will be shown,
47whether the ship is spawned or not.
47whether the ship is spawned or not.
48
48
49−NOTE: Some sigil inputs are considered ambiguous even if they exactly match
49+NOTE: Some sigil inputs are considered ambiguous, even if they exactly match
50a particular sigil, because further details could match a different sigil.
50a particular sigil, because further details could match a different sigil.
51E.g. `~zod` is a circle, but a circle in the suffix position might be intended as a more general search.
51E.g. `~zod` is a circle, but a circle in the suffix position might be intended as a more general search.
52A future version of Astrolabe will allow you to view the ship
52A future version of Astrolabe will allow you to view the ship
@@ -56,7 +56,7 @@ Read more about Sigils [here](/~/scry/docs/usr/astrolabe/sigil.html).
56
56
57## The Star Chart
57## The Star Chart
58
58
59−Click and drag to move your view, use the mouse wheel to zoom in and out. Click on a dot
59+Click and drag to move your view; use the mouse wheel to zoom in and out. Click on a dot
60to see the full Ship View. Enter full `@p`s in the search bar to find a specific point.
60to see the full Ship View. Enter full `@p`s in the search bar to find a specific point.
61
61
62Please note that stars [locked in the Linear Release Contract](/~/scry/docs/usr/astrolabe/star.html)
62Please note that stars [locked in the Linear Release Contract](/~/scry/docs/usr/astrolabe/star.html)
@@ -64,7 +64,7 @@ are not shown in the Star Chart, as they are not yet a part of the network (thou
64been spawned).
64been spawned).
65
65
66The Sponsors/Parents toggle lets you switch between two different views of the network.
66The Sponsors/Parents toggle lets you switch between two different views of the network.
67−The default Sponsors view shows each planet under its sponsoring star, and each
67+The default Sponsors view shows each planet under its sponsoring star and each
68star under its sponsoring galaxy. Planets and Stars without sponsors are not
68star under its sponsoring galaxy. Planets and Stars without sponsors are not
69present in this view.
69present in this view.
70The Parent view simply shows each point under the point that spawned it. All spawned points
70The Parent view simply shows each point under the point that spawned it. All spawned points
@@ -73,7 +73,7 @@ In both views, all galaxies are shown for completeness.
73
73
74## Upcoming Features
74## Upcoming Features
75
75
76−In addition to improving the search features over time, Astrolabe will one day feature ntegrations with Groups, `%pals`, `%gora`, and whatever else seems fun and/or useful.
76+In addition to improving the search features over time, Astrolabe will one day feature integrations with Groups, `%pals`, `%gora`, and whatever else seems fun and/or useful.
77
77
78## Info
78## Info
79
79
desk/doc/usr/sigil-input.udonnew file+27
@@ -0,0 +1,27 @@
1+;>
2+# How to Search by Sigil
3+
4+Use the dropdown at the top to select Galaxy, Star, or Planet.
5+Click on an empty square to start selecting sigil components.
6+
7+Select component categories on the right, and then click the options on the sigil
8+to add them to your search.
9+
10+The ^ button goes up a level so you can select another category.
11+The X button will clear sigil components from the current symbol,
12+except the basic shape. If only the basic shape remains, the X button will clear that.
13+At the top level, the X button will clear all inputs.
14+
15+Your contacts will be searched for any input.
16+When the search has become specific enough,
17+all spawned ships with matching sigils will be shown.
18+If your input is unambiguous, the page for the matching ship will be shown,
19+whether the ship is spawned or not.
20+
21+_NOTE:_ Some sigil inputs are considered ambiguous, even if they exactly match
22+a particular sigil, because further details could match a different sigil.
23+E.g. `~zod` is a circle, but a circle in the suffix position might be intended as a more general search.
24+A future version of Astrolabe will allow you to view the ship
25+whose sigil most closely matches your search, even if the search is ambiguous.
26+
27+_See Also:_ [*What is a Sigil?*](/~/scry/docs/usr/astrolabe/sigil.html)
desk/doc/usr/sigil.udon+3−2
@@ -2,9 +2,9 @@
2# What is a Sigil?
2# What is a Sigil?
3
3
4It's a default profile picture, based on your [`@p`](/~/scry/docs/usr/astrolabe/patpee.html).
4It's a default profile picture, based on your [`@p`](/~/scry/docs/usr/astrolabe/patpee.html).
5−Each 3-letter syllable corresponds to sigil shape, or symbol.
5+Each 3-letter syllable corresponds to a sigil shape, or "symbol".
6Since planet `@p`s have 4 syllables, a planet sigil is a 2x2 grid of 4 symbols.
6Since planet `@p`s have 4 syllables, a planet sigil is a 2x2 grid of 4 symbols.
7−Star sigils have 2 symbols, and galaxies just 1.
7+Star sigils have 2 symbols, and galaxies have just 1.
8
8
9![planet sigils](/apps/astrolabe/sigil-example.png)
9![planet sigils](/apps/astrolabe/sigil-example.png)
10
10
@@ -19,3 +19,4 @@ with a focus on visual design rather than algorithmic purity.
19Tlon saw that Urbit IDs need a visual representation,
19Tlon saw that Urbit IDs need a visual representation,
20so they designed a system for generating default avatars.
20so they designed a system for generating default avatars.
21You can read about it in the blog post [_Creating Sigils_](https://urbit.org/blog/creating-sigils).
21You can read about it in the blog post [_Creating Sigils_](https://urbit.org/blog/creating-sigils).
22+
ui/index.html+1
@@ -8,6 +8,7 @@
8 <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
8 <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
9 <link rel="manifest" href="/site.webmanifest">
9 <link rel="manifest" href="/site.webmanifest">
10 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
10 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11+ <meta name="color-scheme" content="light only">
11 </head>
12 </head>
12 <body>
13 <body>
13 <div id="app" class="h-full"></div>
14 <div id="app" class="h-full"></div>
ui/src/components/search/SearchBar.svelte+1−1
@@ -82,7 +82,7 @@
82 }
82 }
83
83
84 function showSigilDoc() {
84 function showSigilDoc() {
85− docs.show('sigil');
85+ docs.show('sigil-input');
86 }
86 }
87
87
88 const buttonClasses = 'rounded-full bg-black text-white text-sm transition-opacity opacity-50 hover:opacity-80';
88 const buttonClasses = 'rounded-full bg-black text-white text-sm transition-opacity opacity-50 hover:opacity-80';
ui/src/components/search/sigil/SymbolInputModeSelector.svelte+83−54
@@ -14,87 +14,110 @@
14 export let inputComponents: string[] = [];
14 export let inputComponents: string[] = [];
15 export let unfocusSymbol: Function = () => {};
15 export let unfocusSymbol: Function = () => {};
16
16
17− let modes: string[] = [];
17+ let mode: string = null;
18+ let subMode: string = null;
18 let modeDef: ModeDef = undefined;
19 let modeDef: ModeDef = undefined;
20+ let unselectedSubModesExist: boolean = false;
19− let subModeDefs: ModeDefs = MODE_DEFS;
21+ let modeDefs: ModeDefs = MODE_DEFS;
22+ let plausibleModeDefs: { name: string, def: ModeDef }[] = [];
20
23
21 function showGeonSelector() {
24 function showGeonSelector() {
22− if (!symbolQuery.components.length && modes.length == 0) {
25+ if (!symbolQuery.components.length && !mode) {
23− modes = ['geon'];
26+ mode = 'geon';
27+ subMode = null;
24 }
28 }
25 }
29 }
26
30
27 $: symbolQuery.components, showGeonSelector();
31 $: symbolQuery.components, showGeonSelector();
28
32
29− function pushMode(mode: string) {
33+ function pushMode(newMode: string) {
30− if (modeDef?.modes) {
34+ const subModes = modeDef?.modes;
31− modes = [...modes, mode];
35+ if (subModes || subMode) {
36+ subMode = newMode;
32 } else {
37 } else {
33− modes = [...modes.slice(0, -1), mode];
38+ mode = newMode;
39+ subMode = null;
34 }
40 }
35 }
41 }
36
42
37 function popMode() {
43 function popMode() {
38− if (modes.length) {
44+ if (mode || subMode) {
39− if (modeDef?.modes) {
45+ mode = null;
40− modes = modes.slice(0, -1);
46+ subMode = null;
41− } else {
42− modes = modes.slice(0, -2);
43− }
44 } else {
47 } else {
45 unfocusSymbol();
48 unfocusSymbol();
46 }
49 }
47 }
50 }
48
51
49 $: {
52 $: {
53+ let modeResolved = false;
54+ let count = 0;
55+ while (!modeResolved && count < 5) {
50− modeDef = undefined;
56+ modeDef = undefined;
51− subModeDefs = MODE_DEFS;
57+ modeDefs = MODE_DEFS;
52− for (let mode of modes) {
58+ if (mode) {
53− if (modeDef && modeDef.modes) {
59+ modeDef = MODE_DEFS[mode];
54− subModeDefs = modeDef.modes;
60+ }
61+ unselectedSubModesExist = !!modeDef?.modes;
62+ if (unselectedSubModesExist) {
63+ modeDefs = modeDef.modes;
64+ if (subMode) {
65+ if (modeDefs[subMode]) {
66+ modeDef = modeDefs[subMode];
67+ } else {
68+ console.error(`Unknown subMode: ${subMode} of ${mode} in defs:`, modeDefs);
69+ subMode = null;
70+ }
71+ }
55 }
72 }
56− if (subModeDefs[mode]) {
73+ unselectedSubModesExist = !!modeDef?.modes;
57− modeDef = subModeDefs[mode];
74+ if (!isDefPlausible(modeDef) && mode !== 'geon') {
75+ if (subMode) {
76+ subMode = null;
77+ } else {
78+ mode = null;
79+ }
58 } else {
80 } else {
59− console.error(`Unknown mode: ${mode} of ${modes} in defs:`, subModeDefs);
81+ plausibleModeDefs = getPlausibleModeDefs(modeDefs);
82+ if (unselectedSubModesExist) {
83+ subMode = plausibleModeDefs[0].name;
84+ } else {
85+ modeResolved = true;
86+ }
87+ }
88+ count++;
89+ if (count >= 5 && !modeResolved) {
90+ console.error("sigil input mode resulotion failed");
60 }
91 }
61 }
92 }
62−
93+ inputComponents = [];
63− if (modeDef && modeDef.modes) {
64− subModeDefs = modeDef.modes;
65− }
66−
67− if (modeDef?.parts?.length && !modeDef.modes) {
94+ if (modeDef?.parts?.length) {
68 inputComponents = modeDef.parts;
95 inputComponents = modeDef.parts;
69 if (!$searchSettings.allowFictionalSigils) {
96 if (!$searchSettings.allowFictionalSigils) {
70 inputComponents = symbolQuery.filterPlausibleParts(inputComponents);
97 inputComponents = symbolQuery.filterPlausibleParts(inputComponents);
71 }
98 }
72− } else {
73− inputComponents = [];
74 }
99 }
75 }
100 }
76
101
77− $: plausibleModes = Object.entries(subModeDefs).map(([modeName, def]) => {
102+ function isDefPlausible(def: ModeDef): boolean {
103+ if (!def) return true;
78 const deepParts = getDeepParts(def);
104 const deepParts = getDeepParts(def);
79− const plausible = $searchSettings.allowFictionalSigils || symbolQuery.arePartsPlausible(deepParts);
105+ return $searchSettings.allowFictionalSigils || symbolQuery.arePartsPlausible(deepParts);
80− if (!plausible && modeName !== 'geon') return null;
106+ }
81− const parts = filterPartsByGeon(def.displayParts || def.parts, symbolQuery.geon);
82− return { parts, modeName };
83− }).filter(mode => mode !== null);
84
107
85− $: {
108+ function getPlausibleModeDefs(modeDefs: ModeDefs) {
86− const currentMode = modes.slice(-1)[0];
109+ return Object.entries(modeDefs).map(([modeName, def]) => {
87− if (currentMode != 'geon') {
110+ const plausible = isDefPlausible(def);
88− if (plausibleModes.length === 0) {
111+ if (!plausible && modeName !== 'geon') return null;
89− popMode();
112+ const parts = filterPartsByGeon(def.displayParts || def.parts, symbolQuery.geon);
90− } else if (plausibleModes.length >= 1) {
113+ return {
91− const leafMode = modeDef && !(modeDef.modes);
114+ name: modeName,
92− const plausibleModeNames = plausibleModes.map(({ modeName }) => modeName);
115+ def: {
93− if ((modes.length == 1 && modeDef.modes) || (leafMode && !plausibleModeNames.includes(currentMode))) {
116+ ...def,
94− pushMode(plausibleModes[0].modeName);
117+ parts,
95− }
118+ },
96− }
119+ };
97− }
120+ }).filter(mode => mode !== null);
98 }
121 }
99
122
100 function clear() {
123 function clear() {
@@ -116,17 +139,23 @@
116</style>
139</style>
117
140
118<div class="mx-auto flex justify-center xs:items-center xs:flex-col">
141<div class="mx-auto flex justify-center xs:items-center xs:flex-col">
119− <SymbolInputNavButtons onDone={popMode} onClear={clear} />
142+ <SymbolInputNavButtons onDone={popMode} onClear={clear} hideClearButton={symbolQuery.components.length == 0} />
120 <div class="max-w-[15rem] h-full grid grid-cols-custom gap-1 justify-center xs:max-w-[8rem]">
143 <div class="max-w-[15rem] h-full grid grid-cols-custom gap-1 justify-center xs:max-w-[8rem]">
121− {#if modes[0] === 'geon'}
144+ {#if mode === 'geon'}
122 <GeonSelector bind:symbolQuery {popMode} />
145 <GeonSelector bind:symbolQuery {popMode} />
123 {:else}
146 {:else}
124− {#each plausibleModes as { modeName, parts }}
147+ {#each plausibleModeDefs as { name, def: { parts } }}
125− <SymbolInputModeSelectorButton components={parts} focused={modes.slice(-1)[0] === modeName}
148+ <SymbolInputModeSelectorButton components={parts} focused={mode === name || subMode === name}
126− on:click={() => pushMode(modeName)}
149+ on:click={() => pushMode(name)}
127 />
150 />
128 {/each}
151 {/each}
129 {/if}
152 {/if}
130 </div>
153 </div>
154+ <!-- <p class="break-all w-24">
155+ mode: {mode}
156+ </p>
157+ <p class="break-all w-24">
158+ sub: {subMode}
159+ </p> -->
131</div>
160</div>
132
161
ui/src/types/sigil.ts+1−1
@@ -22,7 +22,7 @@ export interface ModeDefs {
22
22
23export const MODE_DEFS: ModeDefs = {
23export const MODE_DEFS: ModeDefs = {
24 geon: {
24 geon: {
25− modes: {},
25+ // modes: {},
26 displayParts: ['ghb'],
26 displayParts: ['ghb'],
27 },
27 },
28 line: {
28 line: {