Merge branch 'pre-beta' into bm/type-docs

This commit is contained in:
bonbud-macryg 2024-08-02 14:08:31 +01:00 committed by GitHub
commit 5d972a796e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 682 additions and 210 deletions

View File

@ -6,7 +6,7 @@
|^
;div.wf.hf.relative
;div.fc.g5.ma.mw-page.p-page
;+ menu
:: ;+ menu
;+ apps
==
==

View File

@ -30,34 +30,6 @@
"""
--{(trip key)}: {(trip val)};
"""
++ theme-style
=/ body-style
"""
body \{
background-color: var(--b1);
background-image: var(--sky-bg-url);
background-size: var(--sky-bg-size);
background-repeat: var(--sky-bg-repeat);
}
"""
=/ settings
^- (unit sky-settings)
=/ s (~(get of:neo kids.bowl) /settings)
?~ s ~
:- ~
!< sky-settings
q.q.saga.u.s
;style
;+ ;/
?~ settings
body-style
"""
{body-style}
html \{
{(map-to-css-tape u.settings)}
}
"""
==
++ icon-url
^~
%- trip
@ -125,26 +97,28 @@
;script
;+ ;/ %- trip
'''
function urbitTimestamp() {
let now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let date = now.getDate();
let hour = String(now.getHours()).padStart(2, '0');
let min = String(now.getMinutes()).padStart(2, '0');
let sec = String(now.getSeconds()).padStart(2, '0');
return `~${year}.${month}.${date}..${hour}.${min}.${sec}`;
}
document.addEventListener('feather-css-change', (e) => {
document.addEventListener('feather-changed', (e) => {
e.detail.forEach(r => {
document.documentElement.style
.setProperty('--'+e.detail.variable, `${e.detail.value}${e.detail.unit||''}`, 'important');
$('wi-nd').poke('feather-css-change', e.detail)
.setProperty('--'+r.variable, `${r.value}${r.unit||''}`);
})
let windows = document.querySelectorAll('wi-nd');
windows.forEach(w => {
$(w).poke('set-feather-values', e.detail)
})
let rules = document.querySelector('s-k-y').currentFeatherRules;
localStorage.setItem('feather-settings', JSON.stringify(rules));
});
let rules = JSON.parse(localStorage.getItem('feather-settings') || '[]');
rules.forEach(r => {
document.documentElement.style
.setProperty('--'+r.variable, `${r.value}${r.unit||''}`);
})
window.addEventListener('resize', () => {
$('s-k-y').attr('open', null);
})
});
window.addEventListener('message', function(event) {
if (event.data?.messagetype !== 'sky-poll-response') return;
if (event.data?.messagetype == 'sky-poll-response') {
let wid = event.data.wid;
let here = event.data.here;
let prefix = event.data.prefix;
@ -152,6 +126,15 @@
if (wind) {
$(wind).poke('iframe-moved', {here, prefix})
}
}
else if (event.data?.messagetype == 'iframe-wants-feather') {
let rules = document.querySelector('s-k-y').currentFeatherRules;
let wid = event.data.wid;
let wind = document.querySelector(`[wid='${wid}']`);
if (wind) {
$(wind).poke('set-feather-values', rules)
}
}
});
'''
==
@ -169,7 +152,6 @@
=hx-replace-url "/neo/sky"
=our (scow %p our.bowl)
;+ in
;+ theme-style
==
==
--

View File

@ -0,0 +1,284 @@
# Axal guide
`+axal` is the recursive tree type that Shrubbery uses to build the namespace.
For userspace developers, axals are useful when you're writing UIs and you want to work with the descendants of whichever shrub you're viewing in the frontend. (e.g. You're rendering a todo item and you want to render its sub-tasks, which are nodes beneath the main task in the namespace.)
We work with axals using the `+of` core defined in `/sur/neo.hoon`, whose arms are documented below.
The `+axal` type itself looks like this.
```
++ axal
|$ [item]
[fil=(unit item) kid=(map iota $)]
```
One way to think of the Shrubbery namespace is as a filesystem, where files could be data, code, or something in between. So the `+axal` represents a directory of such files. The `fil` is the state of the file, which may or may not be null. The `kid` map stores everything below this file in the directory. The map's keys are the path segments immediately below this layer of the directory, and its values are the subtrees that correspond to those paths.
***
## `+del`
Delete a node.
```
++ del
|= pax=pith
^+ fat
?~ pax [~ kid.fat]
=/ kid (~(get by kid.fat) i.pax)
?~ kid fat
fat(kid (~(put by kid.fat) i.pax $(fat u.kid, pax t.pax)))
```
Returns an axal with the node at path `pax` removed.
## `+dip`
Descend to the axal at the given path.
```
++ dip
|= pax=pith
^+ fat
?~ pax fat
=/ kid (~(get by kid.fat) i.pax)
?~ kid [~ ~]
$(fat u.kid, pax t.pax)
```
Returns an axal whose uppermost node is the node at the given path `pax`.
## `+fit`
Fetch file at the longest existing prefix of this path.
```
++ fit
|= pax=pith
^+ [pax fil.fat]
?~ pax [~ fil.fat]
=/ kid (~(get by kid.fat) i.pax)
?~ kid [pax fil.fat]
=/ low $(fat u.kid, pax t.pax)
?~ +.low
[pax fil.fat]
low
```
Returns a `(pair pith *)` where `*` is the node at the given path `pax`.
## `+gas`
Merge a list of `(pair pith *)` with the axal.
(Note: currently broken.)
```
++ gas
|* lit=(list (pair pith _?>(?=(^ fil.fat) u.fil.fat)))
^+ fat
?~ lit fat
$(fat (put p.i.lit q.i.lit), lit t.lit)
```
Returns an axal.
## `+get`
Get a node.
```
++ get
|= pax=pith
fil:(dip pax)
```
Returns a unit of the node.
## `+got`
Get a node, error if the node doesn't exist.
```
++ got
|= pax=pith
~| missing-room/pax
(need (get pax))
```
Returns the node or errors.
## `+gut`
Get a node, with a default to fall back on.
```
++ gut
|* [pax=pith dat=*]
=> .(dat `_?>(?=(^ fil.fat) u.fil.fat)`dat, pax `pith`pax)
^+ dat
(fall (get pax) dat)
```
Returns the node if it exists, return the default noun `dat` if not.
## `+has`
Check if the axal contains a node as this path.
```
++ has
|= pax=pith
!=(~ (get pax))
```
Returns `%.y` if the node exists, `%.n` if not.
## `+kids`
Get the kids of the node at the given path.
```
++ kids
|= pax=pith
^- (axil _?>(?=(^ fil.fat) u.fil.fat))
:- (get pax)
(kid pax)
```
Returns an [`axil`](https://docs.urbit.org/language/hoon/reference/arvo#axil), for secret reasons.
## `+lop`
Recursively remove nodes from the tree.
```
++ lop
|= pax=pith
^+ fat
?~ pax fat
|-
?~ t.pax fat(kid (~(del by kid.fat) i.pax))
=/ kid (~(get by kid.fat) i.pax)
?~ kid fat
fat(kid (~(put by kid.fat) i.pax $(fat u.kid, pax t.pax)))
```
Returns an axal.
If given path `/foo/bar/baz`, `+lop` will remove the nodes at addressses `/foo`, `/bar`, and `/baz`. Removing `/foo` does not remove its children at `/bar` and `/baz`.
## `+parent`
Walk up the axal, starting at the node specified by `cur` to find the closest ancestor node with state.
```
++ parent
=| res=(unit pith)
=| cur=pith
|= pax=pith
|- ^+ res
?~ pax
res
=? res ?=(^ fil.fat)
`cur
=/ nex (~(get by kid.fat) i.pax)
?~ nex
res
$(fat u.nex, pax t.pax, cur (snoc cur i.pax))
```
Returns a `(unit pith)` of the closest ancestor node with state.
## `+put`
Add a node to the axal.
```
++ put
|* [pax=pith dat=*]
^+ fat
=> .(dat `_?>(?=(^ fil.fat) u.fil.fat)`dat, pax `pith`pax)
|- ^+ fat
?~ pax fat(fil `dat)
=/ kid (~(gut by kid.fat) i.pax ^+(fat [~ ~]))
fat(kid (~(put by kid.fat) i.pax $(fat kid, pax t.pax)))
```
Returns an axal with the given node `dat` added at the given path `pax`.
## `+snip`
Prune empty nodes from the descendants of this node.
```
++ snip
|- ^+ fat
=* loop $
%_ fat
kid
%- ~(run by kid.fat)
|= f=_fat
?^ fil.f
[`u.fil.f ~]
loop(fat f)
==
```
Returns an `axal`.
## `+tap`
Flatten the axal into a list.
```
++ tap
=| pax=pith
=| out=(list (pair pith _?>(?=(^ fil.fat) u.fil.fat)))
|- ^+ out
=? out ?=(^ fil.fat) :_(out [pax u.fil.fat])
=/ kid ~(tap by kid.fat)
|- ^+ out
?~ kid out
%= $
kid t.kid
out ^$(pax (weld pax /[p.i.kid]), fat q.i.kid)
==
```
Returns a `(list (pair pith *))` where `*` is the type of the nodes in the axal given as the `+of` door's sample.
## `+tar`
Flatten the axal into a map.
```
++ tar
(~(gas by *(map pith _?>(?=(^ fil.fat) u.fil.fat))) tap)
--
```
Returns a `(map pith *)` where `*` is the type of the node in the axal given as the `+of` door's sample.
## `+view`
View a subtree of the sample axal.
```
++ view
=| res=(map pith _?>(?=(^ fil.fat) u.fil.fat))
|= [=care pax=pith]
=. fat (dip pax)
=? res ?=(^ fil.fat)
(~(put by res) ~ u.fil.fat)
?+ care !!
%x res
%y =.(fat snip (~(uni by res) tar))
%z (~(uni by res) tar)
==
```
Returns a subtree of the sample axal. Depending on the given care this subtree will be the node at the given path, the node and its immediate children, or the entire subtree below the node at the given path.

View File

@ -15,20 +15,57 @@ class extends HTMLElement {
:host {
display: flex;
flex-direction: column;
padding: 8px;
gap: 40px;
}
</style>
<h1>Settings</h1>
<div class="fc g2 p1">
<div class="fc g3">
${this.partSlider('Opacity', 'sky-opacity', null, 0.1, 1, 0.01)}
${this.partSlider('Outer gap size', 'sky-outer-gap', 'px', 0, 30, 1)}
${this.partSlider('Inner gap size', 'sky-inner-gap', 'px', 0, 30, 1)}
</div>
<div class="fc g4">
${this.partSlider('Base font size', '1in', 'px', 1, 8, 0.01)}
${this.partSlider('Monospaced font scale', 'mono-scale', 'px', 0.3, 1.7, 0.01)}
${this.partSlider('Letter spacing', 'letter-spacing', 'px', -1, 3, 0.001)}
${this.partSlider('Line height', 'line-height', null, 1, 2, 0.01)}
${this.partSlider('Line height', 'line-height', null, 0.7, 2, 0.01)}
${this.partDropdown('Main font', 'font', this.mainFonts)}
${this.partDropdown('Monospaced font', 'font-mono', this.monoFonts)}
</div>
<div class="fc g1">
<div class="fr g2">${this.partColor('b4', 'b4')}${this.partColor('f4', 'f4')}</div>
<div class="fr g2">${this.partColor('b3', 'b3')}${this.partColor('f3', 'f3')}</div>
<div class="fr g2">${this.partColor('b2', 'b2')}${this.partColor('f2', 'f2')}</div>
<div class="fr g2">${this.partColor('b1', 'b1')}${this.partColor('f1', 'f1')}</div>
<div class="fr g2">${this.partColor('b0', 'b0')}${this.partColor('f0', 'f0')}</div>
<div class="fr g2">${this.partColor('b-1', 'b-1')}${this.partColor('f-1', 'f-1')}</div>
<div class="fr g2">${this.partColor('b-2', 'b-2')}${this.partColor('f-2', 'f-2')}</div>
<div class="fr g2">${this.partColor('b-3', 'b-3')}${this.partColor('f-3', 'f-3')}</div>
</div>
<div>
<button
class="p-1 br1 b1 bd1"
onclick="$(this).host().poke('reset')"
>
Reset to defaults
</button>
</div>
`
}
connectedCallback() {
$(this).off();
$(this).on('reset', () => {
//
localStorage.removeItem('feather-settings');
document.documentElement.style = '';
this.populateFromCurrent();
});
this.populateFromCurrent();
}
attributeChangedCallback(name, oldValue, newValue) {
//
}
qs(sel) {
return this.shadowRoot.querySelector(sel);
}
@ -38,28 +75,132 @@ class extends HTMLElement {
gid(id) {
return this.shadowRoot.getElementById(id);
}
connectedCallback() {
$(this).off();
get mainFonts() {
return [
"DM Sans"
,"Lato"
,"Georgia"
,"Optima"
,"DejaVu Sans"
,"Palatino"
,"Montserrat"
,"Verdana"
,"Gill Sans"
,"Helvetica Neue"
,"Open Sans"
,"Roboto"
,"Arial"
,"Futura"
,"PT Sans"
]
}
attributeChangedCallback(name, oldValue, newValue) {
//
get monoFonts() {
return [
"Andale Mono"
,"Courier New"
,"Courier"
,"Monaco"
,"Spot Mono"
]
}
get currentFeatherRules() {
// returns array of {variable: '1in', unit: 'px', value: '4'}
let rules = [
{ variable: 'b4', unit: ''},
{ variable: 'b3', unit: ''},
{ variable: 'b2', unit: ''},
{ variable: 'b1', unit: ''},
{ variable: 'b0', unit: ''},
{ variable: 'b-1', unit: ''},
{ variable: 'b-2', unit: ''},
{ variable: 'b-3', unit: ''},
{ variable: 'f4', unit: ''},
{ variable: 'f3', unit: ''},
{ variable: 'f2', unit: ''},
{ variable: 'f1', unit: ''},
{ variable: 'f0', unit: ''},
{ variable: 'f-1', unit: ''},
{ variable: 'f-2', unit: ''},
{ variable: 'f-3', unit: ''},
{ variable: 'font', unit: ''},
{ variable: 'font-mono', unit: ''},
{ variable: 'mono-scale', unit: ''},
{ variable: 'line-height', unit: ''},
{ variable: 'sky-opacity', unit: ''},
{ variable: 'letter-spacing', unit: 'px'},
{ variable: 'sky-outer-gap', unit: 'px'},
{ variable: 'sky-inner-gap', unit: 'px'},
{ variable: '1in', unit: 'px'},
];
let docStyles = getComputedStyle(document.querySelector('s-k-y'));
return rules.map(r => {
let already = docStyles.getPropertyValue(`--${r.variable}`);
let value = !!r.unit?.length ? already.slice(0, 0 - r.unit.length) : already;
return {value, ...r}
})
}
partSlider(label, variable, unit, min, max, step) {
return `
<label class="fc g1">
<span class="s-1 f2">${label}</span>
<input
id="in-${variable}"
class="wf"
type="range"
max="${max || 100}"
min="${min || 0}"
step="${step || 5}"
oninput="this.getRootNode().host.setCss('${variable}', '${unit||''}', this.value)"
oninput="$(this).host().emit('feather-changed', [{
variable:'${variable}',
unit: '${unit||''}',
value: this.value
}])"
/>
</label>
`
}
setCss(variable, unit, value) {
$(this).emit('feather-css-change', {variable, unit, value});
partDropdown(label, variable, options) {
return `
<label class="fc g1">
<span class="s-1 f2">${label}</span>
<select
id="in-${variable}"
class="wf p1 br1 bd1"
type="range"
oninput="$(this).host().emit('feather-changed', [{
variable:'${variable}',
unit: '',
value: this.value
}])"
>
${options.map(o => '<option value="' + o + '">' + o + '</option>')}
</select>
</label>
`
}
partColor(label, variable) {
return `
<label class="fr g1 ac jc grow">
<span class="s-1 f2 mono">${label}</span>
<input
id="in-${variable}"
class="wf fc ac jc br1"
type="color"
oninput="$(this).host().emit('feather-changed', [{
variable:'${variable}',
unit: '',
value: this.value
}])"
/>
</label>
`
}
populateFromCurrent() {
this.currentFeatherRules.forEach(r => {
let el = this.gid(`in-${r.variable}`);
if (el) {
el.value = r.value;
}
});
}
});

View File

@ -1,15 +1,110 @@
/** feather.css
* ~2024.4.6
/* feather.css */
/*
* part 1: resets
*
* styling resets
* and
* utility classes
*/
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
}
/* Prevent font size inflation */
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
margin-block-end: 0;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role='list'],
ol[role='list'] {
list-style: none;
}
/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
line-height: 1.1;
}
button, summary {
cursor: pointer;
}
/* Balance text wrapping on headings */
h1, h2,
h3, h4 {
text-wrap: balance;
}
a {
text-decoration: none;
color: currentColor;
}
/* Make images easier to work with */
img,
picture {
max-width: 100%;
display: block;
}
/* Inherit as much as possible*/
input, button,
textarea, select {
font-family: inherit;
font-size: inherit;
border: inherit;
background: inherit;
color: inherit;
letter-spacing: inherit;
line-height: inherit;
}
textarea {
resize: none;
}
/* Make sure textareas without a rows attribute are not tiny */
textarea:not([rows]) {
min-height: 10em;
}
/* Anything that has been anchored to should have extra scroll margin */
:target {
scroll-margin-block: 5ex;
}
b {
font-weight: bold;
}
i {
font-style: italic;
}
/*
* part 2: variables
*
**/
*/
:root {
--sky-opacity: 0.95;
--sky-outer-gap: 8px;
--sky-inner-gap: 8px;
--font: 'Arial', sans-serif;
--font: 'Arial';
--font-mono: 'Monaco';
--mono-scale: 0.8;
--letter-spacing: 0.024em;
@ -133,30 +228,37 @@
--f4: var(--dark-f4);
}
}
/*
* part 1: page styling
*
*/
* {
/* do i really need this */
font-size: var(--font-size);
}
/*
@media (max-width: 900px) {
:root {
--font-size: calc(1.3 * var(--font-size));
}
}
*/
body {
font-family: var(--font);
letter-spacing: var(--letter-spacing);
background: var(--b0);
color: var(--f0);
line-height: 1;
html {
height: 100%;
}
button {
border: inherit;
background: inherit;
color: inherit;
body {
margin: 0;
height: 100%;
color: var(--f0);
background: var(--b0);
font-feature-settings: normal;
font-variation-settings: normal;
min-height: 100%;
font-family: var(--font), sans-serif;
letter-spacing: var(--letter-spacing);
line-height: var(--line-height);
}
/*
* part 4: utility classes
*
*/
.break {
word-break: break-word;
}
@ -735,3 +837,38 @@ button {
user-select: none;
cursor: pointer;
}
/*
* part 5: input styling
*
*/
input[type=range] {
-webkit-appearance: none;
width: 100%;
height: 5px;
background: var(--f4);
outline: none;
border-radius: 5px;
}
/* Style the slider thumb */
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 8px;
height: 8px;
background: var(--f0);
cursor: pointer;
border-radius: 50%;
border: none;
}
input[type=range]::-moz-range-thumb {
width: 8px;
height: 8px;
background: var(--f0);
cursor: pointer;
border-radius: 50%;
border: none;
}

View File

@ -1,99 +0,0 @@
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
}
/* Prevent font size inflation */
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
margin-block-end: 0;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role='list'],
ol[role='list'] {
list-style: none;
}
/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
line-height: 1.1;
}
button, summary {
cursor: pointer;
}
/* Balance text wrapping on headings */
h1, h2,
h3, h4 {
text-wrap: balance;
}
a {
text-decoration: none;
color: currentColor;
}
/* Make images easier to work with */
img,
picture {
max-width: 100%;
display: block;
}
/* Inherit fonts for inputs and buttons */
input, button,
textarea, select {
font-family: inherit;
font-size: inherit;
border: inherit;
background: inherit;
color: inherit;
}
textarea {
resize: none;
}
/* Make sure textareas without a rows attribute are not tiny */
textarea:not([rows]) {
min-height: 10em;
}
/* Anything that has been anchored to should have extra scroll margin */
:target {
scroll-margin-block: 5ex;
}
html {
height: 100%;
}
body {
margin: 0;
color: var(--f0);
line-height: 1.1;
font-feature-settings: normal;
font-variation-settings: normal;
min-height: 100%;
}
b {
font-weight: bold;
}
i {
font-style: italic;
}

View File

@ -97,7 +97,7 @@ class extends HTMLElement {
display: grid;
grid-area: main;
overflow: hidden;
padding-left: var(--sky-inner-gap);
padding-left: var(--sky-inner-gap, 8px);
}
#s0, #s1, #s2, #s3 {
overflow: auto;
@ -196,7 +196,7 @@ class extends HTMLElement {
main.open-2 #s0,
main.open-3 #s0,
main.open-4 #s0 {
padding-right: var(--sky-inner-gap);
padding-right: var(--sky-inner-gap, 8px);
}
main.open-1 #s1,
main.open-2 #s1 {
@ -204,7 +204,7 @@ class extends HTMLElement {
}
main.open-3 #s1,
main.open-4 #s1 {
padding-bottom: var(--sky-inner-gap);
padding-bottom: var(--sky-inner-gap, 8px);
}
main.open-1 #s2,
main.open-2 #s2,
@ -212,7 +212,7 @@ class extends HTMLElement {
padding-right: 0;
}
main.open-4 #s2 {
padding-right: var(--sky-inner-gap);
padding-right: var(--sky-inner-gap, 8px);
}
/*
* mobile
@ -292,7 +292,7 @@ class extends HTMLElement {
<span class="mso">notifications</span>
</button>
<button
class="p2 br1 bd1 b3 hover f3"
class="p2 br1 bd1 b3 hover f3 hidden"
onclick="this.getRootNode().host.dispatchEvent(new CustomEvent('toggle-settings'))"
>
<span class="mso">settings</span>
@ -408,6 +408,9 @@ class extends HTMLElement {
get our() {
return this.getAttribute('our');
}
get currentFeatherRules() {
return this.qs('feather-settings').currentFeatherRules;
}
get windows() {
let slots = $(this).children('wi-nd[slot]').get().toSorted((a, b) => {
let aSlot = parseFloat(a.getAttribute('slot').slice(1));

View File

@ -190,9 +190,12 @@ class extends HTMLElement {
this.prefixWhichChanged = e.detail.prefix;
$(this).attr('here', e.detail.here);
});
$(this).on('feather-css-change', (e) => {
$(this).on('set-feather-values', (e) => {
$(this.gid('tabs')).children().each(function() {
this.contentWindow.postMessage({ messagetype: "feather-change", ...e.detail});
this.contentWindow.postMessage({
messagetype: "feather-change",
rules: e.detail
});
});
});
}
@ -279,6 +282,12 @@ class extends HTMLElement {
let wid = this.getAttribute('wid');
const inlineScript = iframeDoc.createElement('script');
inlineScript.textContent = `
window.parent.postMessage(
{
messagetype: 'iframe-wants-feather',
wid: '${wid}',
}, '*'
);
window.addEventListener('message', (event) => {
if (event.data?.messagetype === 'sky-poll') {
let windowHere = event.data.here;
@ -288,13 +297,22 @@ class extends HTMLElement {
}
let here = window.location.pathname.slice(${prefix.length});
if (here != windowHere) {
window.parent.postMessage({messagetype: 'sky-poll-response', wid: '${wid}', here: here, prefix: '${prefix}'}, '*');
window.parent.postMessage({
messagetype: 'sky-poll-response',
wid: '${wid}',
here: here,
prefix: '${prefix}'
}, '*');
}
}
else if (event.data?.messagetype === 'feather-change') {
event.data.rules.forEach(r => {
document.documentElement.style
.setProperty('--'+event.data.variable, event.data.value+event.data.unit, 'important');
.setProperty(
'--'+r.variable,
r.value+r.unit,
);
})
}
});
`;

View File

@ -7,6 +7,7 @@
/* introduction
/* developer-environment-setup
/* types
/* axal
^- kook:neo
|%
++ state pro/%home
@ -47,10 +48,11 @@
[#/[p/our.bowl]/home/docs/tutorials/messenger %make %sail `sail/!>([messenger 'prose p-page mw-page ma' ~]) ~]
[#/[p/our.bowl]/home/docs/tutorials/tasks %make %sail `sail/!>([tasks 'prose p-page mw-page ma' ~]) ~]
::
[#/[p/our.bowl]/home/docs/guides %make %folder `folder/!>([%development %feather %types ~]) ~]
[#/[p/our.bowl]/home/docs/guides %make %folder `folder/!>([%development %feather %types %axal-core ~]) ~]
[#/[p/our.bowl]/home/docs/guides/development %make %sail `sail/!>([developer-environment-setup 'prose p-page mw-page ma' ~]) ~]
[#/[p/our.bowl]/home/docs/guides/feather %make %sail `sail/!>([feather-intro 'prose p-page mw-page ma' ~]) ~]
[#/[p/our.bowl]/home/docs/guides/types %make %sail `sail/!>([types 'prose p-page mw-page ma' ~]) ~]
[#/[p/our.bowl]/home/docs/guides/axal-core %make %sail `sail/!>([axal 'prose p-page mw-page ma' ~]) ~]
==
++ poke
|= =pail:neo

View File

@ -67,13 +67,12 @@
=rel "stylesheet"
;
==
;style: {(trip reset)}
;style: {(trip feather)}
;script
;+ ;/
"""
const sharedStyles = new CSSStyleSheet();
sharedStyles.replaceSync(`{(trip reset)}\0a{(trip feather)}`);
sharedStyles.replaceSync(`{(trip feather)}`);
document.adoptedStyleSheets = [sharedStyles];
"""
==
@ -93,6 +92,11 @@
}
return this;
};
jQuery.fn.host = function () {
let first = this[0];
let h = first.getRootNode().host;
return $(h);
}
jQuery.fn.emit = function (name, detail) {
(this[0]).dispatchEvent(
new CustomEvent(