messenger-created

This commit is contained in:
SuperCoolYun 2024-09-27 14:31:34 -04:00
commit c9ad8ca9a3
28 changed files with 2183 additions and 471 deletions

View File

@ -1576,6 +1576,8 @@
(emit (do-card #/[p/our.bowl]/self %make %self ~ ~))
=. run
(emit (do-card #/[p/our.bowl]/srv/tree %make %tree-eyre ~ (~(gas by *crew:neo) src/#/[p/our.bowl] ~)))
=. run
(emit (do-card #/[p/our.bowl]/storage %make %storage ~ ~))
run
++ pess |=(=post:neo (~(pith press post) %out))
++ clay-beak ^- path

View File

@ -1,20 +1,16 @@
customElements.define('s-k-y',
class extends HTMLElement {
static get observedAttributes() {
//
return [
"our",
"open",
"windows-open",
"default-strategies",
];
}
constructor() {
//
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.adoptedStyleSheets = [sharedStyles];
this.shadowRoot.innerHTML = `
customElements.define(
's-k-y',
class extends HTMLElement {
static get observedAttributes() {
//
return ['our', 'open', 'windows-open', 'default-strategies']
}
constructor() {
//
super()
const shadow = this.attachShadow({ mode: 'open' })
shadow.adoptedStyleSheets = [sharedStyles]
this.shadowRoot.innerHTML = `
<style>
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
.mso,
@ -416,304 +412,334 @@ class extends HTMLElement {
</main>
<slot id="default" style="display: none;"></slot>
`
}
get windowsOpen() {
return parseInt(this.getAttribute("windows-open") || "0");
}
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));
let bSlot = parseFloat(b.getAttribute('slot').slice(1));
if (aSlot > bSlot) return 1;
if (aSlot < bSlot) return -1;
return 0;
});
let noslots = $(this).children('wi-nd:not([slot])').get();
return [...slots, ...noslots];
}
qs(sel) {
return this.shadowRoot.querySelector(sel);
}
qsa(sel) {
return this.shadowRoot.querySelectorAll(sel);
}
gid(id) {
return this.shadowRoot.getElementById(id);
}
connectedCallback() {
$(this).off();
$(this).on("sky-open", (e) => {
this.toggleAttribute("open");
$(this).poke('save-layout');
})
$(this).on('fix-slots', () => {
this.fixSlots();
})
$(this).on('new-window', (e) => {
let wind = document.createElement('wi-nd');
let here = `/${this.our}/home`;
$(wind).attr('here', here);
$(wind).attr('renderer', this.chooseStrategy(here));
$(wind).attr('slot', `s-1`);
$(this).append(wind);
this.growFlock();
this.fixSlots();
})
$(this).on('close-window', (e) => {
let wind = $(e.target);
if (wind.attr('slot') != undefined) {
this.shrinkFlock();
}
wind.remove();
this.fixSlots();
this.renderTabs();
})
$(this).on('minimize-window', (e) => {
let wind = $(e.target);
if (wind.attr('slot') != undefined) {
wind.removeAttr('slot');
this.shrinkFlock();
}
this.fixSlots();
this.renderTabs();
})
$(this).on('maximize-window', (e) => {
let wind = $(e.target);
if (!wind.attr('slot')) {
this.growFlock();
}
wind.attr('slot', 's-1');
this.fixSlots();
this.renderTabs();
})
$(this).on('drag-start', (e) => {
$(this.windows).attr('dragging', '');
})
$(this).on('drag-end', (e) => {
$(this.windows).removeAttr('dragging');
})
$(this).on('here-moved', () => {
this.renderTabs();
})
$(this.gid('s0')).off();
$(this.gid('s0')).on('slotchange', (e) => {
this.renderTabs();
});
$(this.gid('s1')).off();
$(this.gid('s1')).on('slotchange', () => {
this.renderTabs();
});
$(this.gid('s2')).off();
$(this.gid('s2')).on('slotchange', () => {
this.renderTabs();
});
$(this.gid('s3')).off();
$(this.gid('s3')).on('slotchange', () => {
this.renderTabs();
});
$(this.gid('default')).off();
$(this.gid('default')).on('slotchange', () => {
this.renderTabs();
});
$(this.gid('nav')).off();
$(this.gid('nav')).on('dragover', (e) => {
e.preventDefault();
})
$(this.gid('nav')).on('drop', (e) => {
e.preventDefault();
let wid = e.originalEvent.dataTransfer.getData('text/plain');
let wind = $(`[wid='${wid}']`);
wind.poke('minimize');
});
//
$(this).on("toggle-notifications", () => {
if (this.getAttribute('open') === 'notifications') {
this.setAttribute('open', '');
} else {
this.setAttribute('open', 'notifications');
}
})
$(this).on("toggle-settings", () => {
if (this.getAttribute('open') === 'settings') {
this.setAttribute('open', '');
} else {
this.setAttribute('open', 'settings');
}
})
$(this).on("toggle-help", () => {
if (this.getAttribute('open') === 'help') {
this.setAttribute('open', '');
} else {
this.setAttribute('open', 'help');
}
})
$(this).on("save-layout", () => {
this.saveLayout();
});
this.qs("main").className = `open-${this.windowsOpen}`;
this.restoreLayout();
}
attributeChangedCallback(name, oldValue, newValue) {
//
if (name === "open") {
$(this.gid('notifications')).addClass('hidden');
$(this.gid('settings')).addClass('hidden');
$(this.gid('help')).addClass('hidden');
$(this.gid('tab-controller')).addClass('hidden');
if (newValue === null) {
$(this).removeClass("open");
} else if (newValue === 'notifications') {
$(this).addClass("open");
$(this.gid('notifications')).removeClass('hidden');
} else if (newValue === 'settings') {
$(this).addClass("open");
$(this.gid('settings')).removeClass('hidden');
} else if (newValue === 'help') {
$(this).addClass("open");
$(this.gid('help')).removeClass('hidden');
} else {
$(this).addClass("open");
$(this.gid('tab-controller')).removeClass('hidden');
}
} else if (name === "windows-open") {
this.qs("main").className = `open-${this.windowsOpen}`;
const script = document.createElement('script')
script.textContent = `
window.addEventListener('message', (event) => {
if (event.origin === window.location.origin){
if(event.data.messagetype === 'new-wind'){
const customEvent = new CustomEvent('new-window', {detail: {href: event.data.href, slot: 's-2'}});
const element = document.querySelector('s-k-y');
if (element) {
element.dispatchEvent(customEvent);
}
}
}else{
return;
}
})`
shadow.appendChild(script)
}
}
get defaultStrategies() {
let strats = this.getAttribute('default-strategies')
return JSON.parse(strats || '{}');
}
chooseStrategy(here) {
let strats = this.defaultStrategies;
let strat = strats[here] || ['/self'];
return strat[0];
}
renderIcon(name) {
let s = document.createElement('span');
s.className = 'mso';
s.textContent = name;
return s;
}
renderTabs() {
let tabs = $(this.gid('tabs'));
tabs.children().remove();
let windowsOpen = this.windowsOpen;
let that = this;
$(this.windows).each(function(i) {
let wind = this;
let tab = document.createElement('div');
$(tab).addClass('b2 br1 fr af js bd1');
if (i < windowsOpen) {
$(tab).addClass('toggled');
}
get windowsOpen() {
return parseInt(this.getAttribute('windows-open') || '0')
}
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))
let bSlot = parseFloat(b.getAttribute('slot').slice(1))
if (aSlot > bSlot) return 1
if (aSlot < bSlot) return -1
return 0
})
let noslots = $(this).children('wi-nd:not([slot])').get()
return [...slots, ...noslots]
}
qs(sel) {
return this.shadowRoot.querySelector(sel)
}
qsa(sel) {
return this.shadowRoot.querySelectorAll(sel)
}
gid(id) {
return this.shadowRoot.getElementById(id)
}
connectedCallback() {
$(this).off()
$(this).on('sky-open', (e) => {
this.toggleAttribute('open')
$(this).poke('save-layout')
})
$(this).on('fix-slots', () => {
this.fixSlots()
})
$(this).on('new-window', (e) => {
let wind = document.createElement('wi-nd')
let here =
e.detail && e.detail.href ? e.detail.href : `/${this.our}/home`
let slot = e.detail && e.detail.slot ? e.detail.slot : `s-1`
$(wind).attr('here', here)
$(wind).attr('renderer', this.chooseStrategy(here))
$(wind).attr('slot', slot)
$(this).append(wind)
this.growFlock()
this.fixSlots()
})
$(this).on('close-window', (e) => {
let wind = $(e.target)
if (wind.attr('slot') != undefined) {
this.shrinkFlock()
}
wind.remove()
this.fixSlots()
this.renderTabs()
})
$(this).on('minimize-window', (e) => {
let wind = $(e.target)
if (wind.attr('slot') != undefined) {
wind.removeAttr('slot')
this.shrinkFlock()
}
this.fixSlots()
this.renderTabs()
})
$(this).on('maximize-window', (e) => {
let wind = $(e.target)
if (!wind.attr('slot')) {
this.growFlock()
}
wind.attr('slot', 's-1')
this.fixSlots()
this.renderTabs()
})
$(this).on('drag-start', (e) => {
$(this.windows).attr('dragging', '')
})
$(this).on('drag-end', (e) => {
$(this.windows).removeAttr('dragging')
})
$(this).on('here-moved', () => {
this.renderTabs()
})
$(this.gid('s0')).off()
$(this.gid('s0')).on('slotchange', (e) => {
this.renderTabs()
})
$(this.gid('s1')).off()
$(this.gid('s1')).on('slotchange', () => {
this.renderTabs()
})
$(this.gid('s2')).off()
$(this.gid('s2')).on('slotchange', () => {
this.renderTabs()
})
$(this.gid('s3')).off()
$(this.gid('s3')).on('slotchange', () => {
this.renderTabs()
})
$(this.gid('default')).off()
$(this.gid('default')).on('slotchange', () => {
this.renderTabs()
})
let mux = document.createElement('button');
mux.className = "b2 hover br1 bd0 p2 grow tl fr g2 ac js"
mux.style = "overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: left;"
let im = wind.getAttribute('favicon') ? `
<img src="${wind.getAttribute('favicon')}" style="width: 20px; height: 20px;" />
` : ``;
mux.innerHTML = `
$(this.gid('nav')).off()
$(this.gid('nav')).on('dragover', (e) => {
e.preventDefault()
})
$(this.gid('nav')).on('drop', (e) => {
e.preventDefault()
let wid = e.originalEvent.dataTransfer.getData('text/plain')
let wind = $(`[wid='${wid}']`)
wind.poke('minimize')
})
//
$(this).on('toggle-notifications', () => {
if (this.getAttribute('open') === 'notifications') {
this.setAttribute('open', '')
} else {
this.setAttribute('open', 'notifications')
}
})
$(this).on('toggle-settings', () => {
if (this.getAttribute('open') === 'settings') {
this.setAttribute('open', '')
} else {
this.setAttribute('open', 'settings')
}
})
$(this).on('toggle-help', () => {
if (this.getAttribute('open') === 'help') {
this.setAttribute('open', '')
} else {
this.setAttribute('open', 'help')
}
})
$(this).on('save-layout', () => {
this.saveLayout()
})
this.qs('main').className = `open-${this.windowsOpen}`
this.restoreLayout()
}
attributeChangedCallback(name, oldValue, newValue) {
//
if (name === 'open') {
$(this.gid('notifications')).addClass('hidden')
$(this.gid('settings')).addClass('hidden')
$(this.gid('help')).addClass('hidden')
$(this.gid('tab-controller')).addClass('hidden')
if (newValue === null) {
$(this).removeClass('open')
} else if (newValue === 'notifications') {
$(this).addClass('open')
$(this.gid('notifications')).removeClass('hidden')
} else if (newValue === 'settings') {
$(this).addClass('open')
$(this.gid('settings')).removeClass('hidden')
} else if (newValue === 'help') {
$(this).addClass('open')
$(this.gid('help')).removeClass('hidden')
} else {
$(this).addClass('open')
$(this.gid('tab-controller')).removeClass('hidden')
}
} else if (name === 'windows-open') {
this.qs('main').className = `open-${this.windowsOpen}`
}
}
get defaultStrategies() {
let strats = this.getAttribute('default-strategies')
return JSON.parse(strats || '{}')
}
chooseStrategy(here) {
let strats = this.defaultStrategies
let strat = strats[here] || ['/self']
return strat[0]
}
renderIcon(name) {
let s = document.createElement('span')
s.className = 'mso'
s.textContent = name
return s
}
renderTabs() {
let tabs = $(this.gid('tabs'))
tabs.children().remove()
let windowsOpen = this.windowsOpen
let that = this
$(this.windows).each(function (i) {
let wind = this
let tab = document.createElement('div')
$(tab).addClass('b2 br1 fr af js bd1')
if (i < windowsOpen) {
$(tab).addClass('toggled')
}
let mux = document.createElement('button')
mux.className = 'b2 hover br1 bd0 p2 grow tl fr g2 ac js'
mux.style =
'overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: left;'
let im = wind.getAttribute('favicon')
? `
<img src="${wind.getAttribute(
'favicon'
)}" style="width: 20px; height: 20px;" />
`
: ``
mux.innerHTML = `
${im}
<span style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: left;">
${$(wind).attr('tab-title') || $(wind).attr('here')}
</span>
`;
let max = $(mux);
$(max).on('click', () => {
$(wind).emit('maximize-window');
});
`
let max = $(mux)
$(max).on('click', () => {
$(wind).emit('maximize-window')
})
let min = document.createElement('button');
$(min).append(that.renderIcon('minimize'));
$(min).addClass('b2 hover br1 bd0 p1 f3');
$(min).on('click', () => {
$(wind).emit('minimize-window');
});
if (i >= windowsOpen) {
$(min).hide();
}
let close = document.createElement('button');
$(close).append(that.renderIcon('close'));
$(close).addClass('b2 hover br1 bd0 p1 f3');
$(close).on('click', () => {
$(wind).emit('close-window');
});
$(tab).append(max);
$(tab).append(min);
$(tab).append(close);
tabs.append(tab);
})
$(this).poke('save-layout');
}
fixSlots() {
let slotted = $(this.windows).filter('[slot]').get().slice(0, 3);
$(this.windows).removeAttr('slot');
slotted.forEach((s, i) => {
s.setAttribute('slot', `s${i}`);
})
}
growFlock() {
$(this).attr('windows-open', Math.min(3, this.windowsOpen + 1));
}
shrinkFlock() {
$(this).attr('windows-open', Math.max(0, this.windowsOpen - 1));
}
saveLayout() {
let layout = {
open: this.hasAttribute('open'),
windowsOpen: parseInt(this.getAttribute('windows-open')),
windows: $(this).children('wi-nd').get().map(w => {
return {
here: w.getAttribute('here'),
slot: w.getAttribute('slot'),
strategies: w.getAttribute('strategies'),
renderer: w.getAttribute('renderer'),
let min = document.createElement('button')
$(min).append(that.renderIcon('minimize'))
$(min).addClass('b2 hover br1 bd0 p1 f3')
$(min).on('click', () => {
$(wind).emit('minimize-window')
})
if (i >= windowsOpen) {
$(min).hide()
}
let close = document.createElement('button')
$(close).append(that.renderIcon('close'))
$(close).addClass('b2 hover br1 bd0 p1 f3')
$(close).on('click', () => {
$(wind).emit('close-window')
})
$(tab).append(max)
$(tab).append(min)
$(tab).append(close)
tabs.append(tab)
})
$(this).poke('save-layout')
}
fixSlots() {
let slotted = $(this.windows).filter('[slot]').get().slice(0, 3)
$(this.windows).removeAttr('slot')
slotted.forEach((s, i) => {
s.setAttribute('slot', `s${i}`)
})
}
localStorage.setItem('sky-layout', JSON.stringify(layout))
}
restoreLayout() {
let layoutString = localStorage.getItem('sky-layout');
if (!!layoutString) {
let layout = JSON.parse(layoutString);
$(this).attr('open', layout.open ? '' : null);
$(this).attr('windows-open', `${layout.windowsOpen}`);
$(this).children('wi-nd').remove();
layout.windows.forEach(w => {
let wind = document.createElement('wi-nd');
$(wind).attr('here', w.here);
$(wind).attr('renderer', w.renderer);
$(wind).attr('strategies', w.strategies);
$(wind).attr('slot', !!w.slot ? w.slot : null);
$(this).append(wind);
})
} else {
// create initial layout
growFlock() {
$(this).attr('windows-open', Math.min(3, this.windowsOpen + 1))
}
shrinkFlock() {
$(this).attr('windows-open', Math.max(0, this.windowsOpen - 1))
}
saveLayout() {
let layout = {
open: false,
windowsOpen: 1,
windows: [
{
here: `/${this.our}/home`,
renderer: `/hawk`,
strategies: ``,
slot: 's0'
}
]
open: this.hasAttribute('open'),
windowsOpen: parseInt(this.getAttribute('windows-open')),
windows: $(this)
.children('wi-nd')
.get()
.map((w) => {
return {
here: w.getAttribute('here'),
slot: w.getAttribute('slot'),
strategies: w.getAttribute('strategies'),
renderer: w.getAttribute('renderer')
}
})
}
localStorage.setItem('sky-layout', JSON.stringify(layout))
this.restoreLayout();
}
restoreLayout() {
let layoutString = localStorage.getItem('sky-layout')
if (!!layoutString) {
let layout = JSON.parse(layoutString)
$(this).attr('open', layout.open ? '' : null)
$(this).attr('windows-open', `${layout.windowsOpen}`)
$(this).children('wi-nd').remove()
layout.windows.forEach((w) => {
let wind = document.createElement('wi-nd')
$(wind).attr('here', w.here)
$(wind).attr('renderer', w.renderer)
$(wind).attr('strategies', w.strategies)
$(wind).attr('slot', !!w.slot ? w.slot : null)
$(this).append(wind)
})
} else {
// create initial layout
let layout = {
open: false,
windowsOpen: 1,
windows: [
{
here: `/${this.our}/home`,
renderer: `/hawk`,
strategies: ``,
slot: 's0'
}
]
}
localStorage.setItem('sky-layout', JSON.stringify(layout))
this.restoreLayout()
}
}
}
});
)

View File

@ -1,25 +1,26 @@
customElements.define('wi-nd',
class extends HTMLElement {
static get observedAttributes() {
//
return [
"wid",
"here",
"searching", // boolean. true is user is using the search bar in the header
"strategies", // space-separated list of iframe prefixes
"renderer", // current iframe strategy
"menu",
"dragging",
"tab-title",
"favicon",
];
}
constructor() {
//
super();
const shadow = this.attachShadow({ mode: 'open' });
shadow.adoptedStyleSheets = [sharedStyles];
this.shadowRoot.innerHTML = `
customElements.define(
'wi-nd',
class extends HTMLElement {
static get observedAttributes() {
//
return [
'wid',
'here',
'searching', // boolean. true is user is using the search bar in the header
'strategies', // space-separated list of iframe prefixes
'renderer', // current iframe strategy
'menu',
'dragging',
'tab-title',
'favicon'
]
}
constructor() {
//
super()
const shadow = this.attachShadow({ mode: 'open' })
shadow.adoptedStyleSheets = [sharedStyles]
this.shadowRoot.innerHTML = `
<style>
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200');
.mso,
@ -102,6 +103,12 @@ class extends HTMLElement {
>
<span class="mso">close</span>
</button>
<button
class="p1 s-1 b2 hover br1 fc jc ac"
id="copy-pith"
>
<span class="mso">content_copy</span>
</button>
<div
class="p1 s-1 b2 grabber f4 fc jc ac"
draggable="true"
@ -117,87 +124,100 @@ class extends HTMLElement {
<div id="tabs" class="fc grow">
</div>
`
this.intervalId = null;
}
connectedCallback() {
$(this.gid('searchbar')).off();
$(this.gid('searchbar')).on('submit', (e) => {
e.preventDefault();
this.setAttribute('here', $(this.gid('input-here')).val());
this.setAttribute('renderer', this.strategies[0]);
this.rebuildIframe();
});
$(this.gid('input-here')).off();
$(this.gid('input-here')).on('focusout', (e) => {
$(this).removeAttr('searching');
});
$(this.gid('input-here')).on('blur', (e) => {
$(this).removeAttr('searching');
});
$(this.gid('menu-toggle')).off();
$(this.gid('menu-toggle')).on('click', (e) => {
this.toggleAttribute('menu');
});
this.intervalId = null
}
connectedCallback() {
$(this.gid('searchbar')).off()
$(this.gid('searchbar')).on('submit', (e) => {
e.preventDefault()
this.setAttribute('here', $(this.gid('input-here')).val())
this.setAttribute('renderer', this.strategies[0])
this.rebuildIframe()
})
$(this.gid('input-here')).off()
$(this.gid('input-here')).on('focusout', (e) => {
$(this).removeAttr('searching')
})
$(this.gid('input-here')).on('blur', (e) => {
$(this).removeAttr('searching')
})
$(this.gid('menu-toggle')).off()
$(this.gid('menu-toggle')).on('click', (e) => {
this.toggleAttribute('menu')
})
$(this.gid('dragger')).off();
$(this.gid('dragger')).on('dragstart', (e) => {
e.originalEvent.dataTransfer.setData('text/plain', this.getAttribute('wid'));
})
$(this.gid('dragger')).on('dragenter', (e) => {
$(this).emit('drag-start');
})
$(this.gid('dragger')).on('dragend', (e) => {
$(this).emit('drag-end');
})
$(this.gid('dragger')).off()
$(this.gid('dragger')).on('dragstart', (e) => {
e.originalEvent.dataTransfer.setData(
'text/plain',
this.getAttribute('wid')
)
})
$(this.gid('dragger')).on('dragenter', (e) => {
$(this).emit('drag-start')
})
$(this.gid('dragger')).on('dragend', (e) => {
$(this).emit('drag-end')
})
$(this).off();
$(this).on('close', () => {
$(this).emit('close-window');
})
$(this).on('minimize', () => {
$(this).emit('minimize-window');
})
$(this).on('dragenter', (e) => {
$(this).addClass('dragging');
})
$(this).on('dragover', (e) => {
e.preventDefault();
})
$(this).on('dragleave', (e) => {
$(this).removeClass('dragging');
})
$(this).on('drop', (e) => {
e.preventDefault();
$(this).emit('drag-end');
let wid = e.originalEvent.dataTransfer.getData('text/plain');
let wind = $(`[wid='${wid}']`);
let newSlot = parseInt(this.getAttribute('slot').slice(1));
let oldSlot = parseInt(wind.attr('slot')?.slice(1));
if (!isNaN(oldSlot) && oldSlot < newSlot) {
newSlot = newSlot + 0.5;
} else {
newSlot = newSlot - 0.5;
}
wind.attr('slot', `s${newSlot}`);
$(this).emit('fix-slots');
})
this.setAttribute('wid', `${Date.now()}`);
this.buildMenu()
$(this).off()
$(this).on('close', () => {
$(this).emit('close-window')
})
$(this).on('minimize', () => {
$(this).emit('minimize-window')
})
$(this.gid('copy-pith')).on('click', async (e) => {
let here = this.getAttribute('here')
try {
await navigator.clipboard.writeText(here)
} catch (err) {
console.error('Failed to copy text: ', err)
}
})
$(this).on('dragenter', (e) => {
$(this).addClass('dragging')
})
$(this).on('dragover', (e) => {
e.preventDefault()
})
$(this).on('dragleave', (e) => {
$(this).removeClass('dragging')
})
$(this).on('drop', (e) => {
e.preventDefault()
$(this).emit('drag-end')
let wid = e.originalEvent.dataTransfer.getData('text/plain')
let wind = $(`[wid='${wid}']`)
let newSlot = parseInt(this.getAttribute('slot').slice(1))
let oldSlot = parseInt(wind.attr('slot')?.slice(1))
if (!isNaN(oldSlot) && oldSlot < newSlot) {
newSlot = newSlot + 0.5
} else {
newSlot = newSlot - 0.5
}
wind.attr('slot', `s${newSlot}`)
$(this).emit('fix-slots')
})
this.setAttribute('wid', `${Date.now()}`)
this.buildMenu()
// poll iframes for changes every 350ms
this.intervalId = setInterval(() => {
let here = this.getAttribute('here');
let favicon = this.getAttribute('favicon');
let tabTitle = this.getAttribute('tab-title');
$(this.gid('tabs')).children().each(function() {
this.contentWindow.postMessage({
messagetype: "sky-poll",
here,
favicon,
tabTitle,
});
});
}, 350);
// poll iframes for changes every 350ms
this.intervalId = setInterval(() => {
let here = this.getAttribute('here')
let favicon = this.getAttribute('favicon')
let tabTitle = this.getAttribute('tab-title')
$(this.gid('tabs'))
.children()
.each(function () {
this.contentWindow.postMessage({
messagetype: 'sky-poll',
here,
favicon,
tabTitle
})
})
}, 350)
$(this).on('title-changed', (e) => {
if (!!e.detail) {
@ -359,51 +379,52 @@ class extends HTMLElement {
if (words.length != 2) {
words = ["b", "b-error"];
}
return words[1].split('-').slice(1).join(' ');
},
}
}
}
labelLookup(renderer) {
let entries = Object.entries(this.rendererLabels);
let entry = entries.filter(([k, v]) => renderer.startsWith(k))[0];
if (!entry) return;
return entry[1](renderer);
}
get prettyCurrent() {
let r = this.renderer;
let m = this.labelLookup(r)
if (m) {
return m;
labelLookup(renderer) {
let entries = Object.entries(this.rendererLabels)
let entry = entries.filter(([k, v]) => renderer.startsWith(k))[0]
if (!entry) return
return entry[1](renderer)
}
return r
}
createIframe(prefix, here, open) {
let el = document.createElement('iframe');
el.setAttribute('prefix', prefix);
el.setAttribute('lazy', '');
el.setAttribute('src', prefix+here);
el.setAttribute('style', 'width: 100%; flex-grow: 1; border: none; background: var(--b0);');
if (!open) {
el.hidden = true;
get prettyCurrent() {
let r = this.renderer
let m = this.labelLookup(r)
if (m) {
return m
}
return r
}
el.addEventListener('load', () => {
this.registerServiceWorker(el, prefix);
});
return el;
}
rebuildIframe() {
$(this.gid('tabs')).children().remove();
let frame = this.createIframe(this.renderer, this.here, true);
$(this.gid('tabs')).append(frame);
}
registerServiceWorker(iframe, prefix) {
// for convenience, this part is inject by wi-nd.
// in future, due to the need to sandbox the iframes,
// this must be provided by the iframe's contents.
const iframeDoc = iframe.contentWindow.document;
let wid = this.getAttribute('wid');
const inlineScript = iframeDoc.createElement('script');
inlineScript.textContent = `
createIframe(prefix, here, open) {
let el = document.createElement('iframe')
el.setAttribute('prefix', prefix)
el.setAttribute('lazy', '')
el.setAttribute('src', prefix + here)
el.setAttribute(
'style',
'width: 100%; flex-grow: 1; border: none; background: var(--b0);'
)
if (!open) {
el.hidden = true
}
el.addEventListener('load', () => {
this.registerServiceWorker(el, prefix)
})
return el
}
rebuildIframe() {
$(this.gid('tabs')).children().remove()
let frame = this.createIframe(this.renderer, this.here, true)
$(this.gid('tabs')).append(frame)
}
registerServiceWorker(iframe, prefix) {
// for convenience, this part is inject by wi-nd.
// in future, due to the need to sandbox the iframes,
// this must be provided by the iframe's contents.
const iframeDoc = iframe.contentWindow.document
let wid = this.getAttribute('wid')
const inlineScript = iframeDoc.createElement('script')
inlineScript.textContent = `
window.parent.postMessage(
{
messagetype: 'iframe-wants-feather',
@ -564,31 +585,32 @@ class extends HTMLElement {
<div class="frw g2 ac js">
</div>
</div>
`);
//
this.strategies.forEach(s => {
let bookmark = $(`<button class="b1 br1 bd1 p-1 wfc"></button>`);
bookmark.text(this.labelLookup(s) || s);
$(bookmark).on('click', (e) => {
$(this).attr('renderer', s)
`)
//
this.strategies.forEach((s) => {
let bookmark = $(`<button class="b1 br1 bd1 p-1 wfc"></button>`)
bookmark.text(this.labelLookup(s) || s)
$(bookmark).on('click', (e) => {
$(this).attr('renderer', s)
})
if (s === this.renderer) {
$(bookmark).addClass('toggled')
}
bookmarks.find('.frw').append(bookmark)
})
if (s === this.renderer) {
$(bookmark).addClass('toggled');
}
bookmarks.find('.frw').append(bookmark);
})
menu.appendChild(bookmarks.get(0));
//
let any = $(`
menu.appendChild(bookmarks.get(0))
//
let any = $(`
<form class="fr g1 af js wf" onsubmit="event.preventDefault()">
<input type="text" class="grow br1 bd1 p-1 b0 wf" autocomplete="off" required placeholder="/any/renderer" />
<button class="p-1 br1 bd1 b1 hover">submit</button>
</form>
`);
any.on('submit', (e) => {
e.preventDefault();
$(this).attr('renderer', any.find('input').val());
})
menu.appendChild(any.get(0));
`)
any.on('submit', (e) => {
e.preventDefault()
$(this).attr('renderer', any.find('input').val())
})
menu.appendChild(any.get(0))
}
}
});
)

View File

@ -0,0 +1,45 @@
/@ comment
/@ meta-social
/- su=shrub-utils
^- kook:neo
|%
++ state pro/%comments
++ poke (sy %meta-social ~)
++ kids
:+ ~ %y
%- ~(gas by *lads:neo)
:~ :- &
[pro/%comments (sy %meta-social ~)]
==
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
:- ~
?~ pal
comments/!>(~)
=+ !<(=meta-social q:(need pal))
~& meta-social
?> ?=(%comment -.meta-social)
comments/!>(+.meta-social)
::
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> ?=(%meta-social stud)
~& kids/(kids-at-pith:su kids.bowl /)
~& 'got poke'
=/ state !<((set comment) q.pail)
=/ diff !<(meta-social vax)
~& diff
?> ?=(%comment -.diff)
=/ new-state
%- ~(uni in state) +.diff
~& new-state
:_ comments/!>(new-state)
~
--
--

View File

@ -28,7 +28,8 @@
|= old=(unit pail:neo)
^- (quip card:neo pail:neo)
:_ home/!>(*home)
:~ [#/[p/our.bowl]/home/diary %make %diary ~ ~]
:~
[#/[p/our.bowl]/home/diary %make %diary ~ ~]
[#/[p/our.bowl]/home/tasks %make %task `task/!>(['' | & ~]) ~]
[#/[p/our.bowl]/home/sail %make %sail `sail/!>(['# hello world' 'prose p-page mw-page ma' ~]) ~]
[#/[p/our.bowl]/home/accel %make %accel ~ ~]
@ -51,13 +52,13 @@
[#/[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/axal-core %make %sail `sail/!>([axal 'prose p-page mw-page ma' ~]) ~]
[#/[p/our.bowl]/home/feed %make %timeline ~ (~(gas by *conf:neo) [%src #/[p/our.bowl]/sky/strategy/[p/our.bowl]] ~)]
::
[#/[p/our.bowl]/sky/strategy/[p/our.bowl]/home %make %order `order/!>([#/hawk ~]) ~]
==
++ poke
|= =pail:neo
|= [=stud:neo =vase]
^- (quip card:neo pail:neo)
?+ p.pail !!
?+ stud !!
%home
[~ pail]
==

View File

@ -0,0 +1,197 @@
/@ ui-event
/@ comment
/- su=shrub-utils
^- kook:neo
=<
|%
++ state pro/%manx
++ poke (sy %ui-event %rely ~)
++ kids *kids:neo
++ deps
^- deps:neo
%- my
:~ :^ %src | [pro/%comments (sy %meta-diff ~)]
~
==
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
::
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
=/ meta=(pair pith:neo lore:neo) (~(got by deps.bowl) %src)
?~ (get-vase-by-pith:su q.meta /)
=/ diff
[(oust [0 2] p.meta) [%comment ~]]
=/ id (en-tape:pith:neo p:meta)
:_ manx/!>((render ~ id bowl))
~
:::~ [/[p/our.bowl]/storage %poke storage-diff/!>(diff)]
::==
=/ render-data (get-comments deps.bowl)
[~ manx/!>((render -.render-data +.render-data bowl))]
::
++ poke
|= [sud=stud:neo vaz=vase]
^- (quip card:neo pail:neo)
?+ sud ~|(bad-stud/stud !!)
%ui-event
=/ eve !<(ui-event vaz)
?> ?=([%submit %meta %comment ~] path.eve)
=/ txt=@t (~(got by data.eve) 'comment')
=/ create=pith:neo (oust [0 2] p:(~(got by deps.bowl) %src))
=/ dif [%comment (sy [now.bowl our.bowl txt] ~)]
:_ pail
:~
[/[p/our.bowl]/storage %poke storage-diff/!>([create dif])]
==
%rely
=/ render-data (get-comments deps.bowl)
[~ manx/!>((render -.render-data +.render-data bowl))]
==
::
--
--
::
|%
++ render
|_ [meta=(set comment) id=tape =bowl:neo]
++ $
^- manx
;div.fc.g1
=style "margin-top: 0.5rem;"
;+ buttons
;div.b1.p2.bd2.br2.hidden
=style "border-color: var(--b1)"
=id (welp "wrapper" id)
;+ comment-form
;+ comments
==
==
++ buttons
;div.fr.je.g1
;button.bd1.br3.b2.hover
=onclick (welp "this.parentNode.nextSibling.children[0].classList.toggle('hidden'); " hidden-logic)
;span
=style "padding: 1px;"
; +
==
==
;+
?~ meta
;div.hidden;
;button.bd1.br3.b2.hover
=onclick (welp "this.parentNode.nextSibling.children[1].classList.toggle('hidden'); " hidden-logic)
;span: 💬
==
==
::
++ comment-form
;form.fr.hidden.g1.b1
=style "border-color: var(--b0)"
=id (welp "form" id)
=event "/submit/meta/comment"
;input.p2.grow.b0.bd2.br2
=style "border-color: var(--b1)"
=type "text"
=required ""
=name "comment"
=placeholder "comment"
;
==
;button.loader.bd2.br2.p2.b0.hover
=style "border-color: var(--b1)"
=onclick (welp "this.parentNode.classList.add('hidden'); " hidden-logic)
=type "submit"
;span.loaded: send
;span.loading: loading
==
==
::
++ comments
;div.hidden.fc.g1.mt1
=id (welp "comments" id)
;*
=/ comments ~(tap in meta)
=/ sorted
%+ sort comments
|= [a=comment b=comment]
(gte when.a when.b)
%+ turn sorted
comment-view
==
++ comment-view
|= =comment
^- manx
;div.fc.wf
;div.fr.jb
;p.f1.p1: {(scow %p from.comment)}
;p.f1: {(pretty-date when.comment bowl)}
==
;div.hfc.fc.as.p4.wf.bd2.br2.b2
=style "border-color: var(--b1)"
;p.grow: {(trip txt.comment)}
==
;imp_mast-meta-reaction: {(welp (en-tape:pith:neo /[p/our.bowl]/storage/reactions/[p/our.bowl]/home/feed) id)}
:: ;imp_mast-meta-comment: {(welp (en-tape:pith:neo /[p/our.bowl]/storage/comments/[p/our.bowl]/home/feed) id)}
==
++ hidden-logic
=/ id-form (welp "form" id)
=/ id-wrapper (welp "wrapper" id)
=/ id-comments (welp "comments" id)
;: weld
%- trip
'if (document.getElementById(\''
id-comments
%- trip
'\').classList.contains("hidden") & document.getElementById(\''
id-form
%- trip
'\').classList.contains("hidden")) { document.getElementById(\''
id-wrapper
%- trip
'\').classList.add("hidden") }else{ document.getElementById(\''
id-wrapper
%- trip
'\').classList.remove("hidden") };'
==
--
::
++ get-comments
|= deps=(map term (pair pith:neo lore:neo))
^- [(set comment) tape]
=/ meta=(pair pith:neo lore:neo) (~(got by deps) %src)
=/ uvase=(unit vase) ::(get-vase-saga-by-pith:su q.meta /)
=/ idea=(unit idea:neo) (~(get of:neo q.meta) /)
?~ idea ~
`q.q.saga:(need idea)
=/ here (en-tape:pith:neo p:(~(got by deps) %src))
?~ uvase `here
:- !<((set comment) (need uvase))
here
::
++ pretty-date
|= [date=@da =bowl:neo]
^- tape
=/ d (yore date)
=/ months
^- (list tape)
:~
"Jan"
"Feb"
"Mar"
"Apr"
"May"
"Jun"
"Jul"
"Aug"
"Sep"
"Oct"
"Nov"
"Dec"
==
?: &(=(m:d m:(yore now.bowl)) =(d:t:d d:t:(yore now.bowl)))
"{(y-co:co h:t:d)}:{(y-co:co m:t:d)}"
"{(y-co:co h:t:d)}:{(y-co:co m:t:d)} {(snag (dec m:d) months)}{(y-co:co d:t:d)}"
--

View File

@ -0,0 +1,179 @@
/@ ui-event
/@ reaction
/- su=shrub-utils
^- kook:neo
=<
|%
++ state pro/%manx
++ poke (sy %ui-event %rely ~)
++ kids *kids:neo
++ deps
^- deps:neo
%- my
:~ :^ %src | [pro/%reactions (sy %meta-diff ~)]
~
==
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
::
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
=/ meta=(pair pith:neo lore:neo) (~(got by deps.bowl) %src)
?~ (get-vase-by-pith:su q.meta /)
=/ diff
[(oust [0 2] p.meta) [%reaction ~]]
=/ id (en-tape:pith:neo p:meta)
:_ manx/!>((render ~ id bowl))
~
:::~ [/[p/our.bowl]/storage %poke storage-diff/!>(diff)]
::==
=/ render-data (get-reactions deps.bowl)
[~ manx/!>((render -.render-data +.render-data bowl))]
::
++ poke
|= [sud=stud:neo vaz=vase]
^- (quip card:neo pail:neo)
?+ sud ~|(bad-stud/stud !!)
%ui-event
=/ eve !<(ui-event vaz)
?>
?|
?=([%change %meta %reaction ~] path.eve)
?=([%click %meta %reaction ~] path.eve)
==
=/ emoji=@t (~(got by data.eve) '/target/value')
=/ create=pith:neo (oust [0 2] p:(~(got by deps.bowl) %src))
=/ dif [%reaction (sy [our.bowl emoji] ~)]
:_ pail
:~
[/[p/our.bowl]/storage %poke storage-diff/!>([create dif])]
==
%rely
=/ render-data (get-reactions deps.bowl)
[~ manx/!>((render -.render-data +.render-data bowl))]
==
::
--
--
::
|%
++ render
|_ [meta=(set reaction) id=tape =bowl:neo]
++ $
^- manx
;div.fc.g1
=style "margin-top: 0.5rem;"
;+ script
;+ event-listener
;+ buttons
==
::
++ script
;script
=type "module"
=src "https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"
;
==
::
++ event-listener
;script
;+ ;/
"""
document.addEventListener('DOMContentLoaded', () => \{
document.getElementById('picker-{id}').addEventListener('emoji-click', event => \{
let reactionInput = document.getElementById('picker-{id}').parentNode.children[0]
reactionInput.setAttribute('value', event.detail.unicode);
const changeEvent = new Event('change', \{
bubbles: true,
cancelable: true
});
reactionInput.dispatchEvent(changeEvent);
});
});
"""
==
::
++ buttons
;div.fc.je.g1
;div.fr.je.g1
;+ reactions-view
;button.bd1.br3.b2.hover
=onclick "this.parentElement.nextSibling.classList.toggle('hidden');"
;span
=style "padding: 1px;"
; ❤️
==
==
==
;div.hidden.fr.je
=style "position: relative;"
;input.hidden
=event "/change/meta/reaction"
=return "/target/value"
;
==
;emoji-picker
=style "position: absolute; height: 250px; --num-columns: 5; --background: rgba(0, 0, 0, 0.1); --border-radius: var(--br3);"
=id (weld "picker-" id)
;
==
==
==
::
++ reactions-view
;div.fr.g1
=id (welp "react" id)
;*
=/ reactions=(list [reaction=@t num=@ud data=(list reaction)])
::%+ sort
(sort-reactions ~(tap in meta))
::aor
%+ turn reactions
|= r=[reaction=@t num=@ud data=(list reaction)]
^- manx
;button.bd1.br3.b2.hover.fr.g1
=event "/click/meta/reaction"
=return "/target/value"
=value (trip reaction.r)
;span
=style "padding: 1px;"
; {(trip reaction.r)}
==
;+ ?. (gth num.r 1)
;div.hidden;
;span: {<num.r>}
==
==
--
::
++ get-reactions
|= deps=(map term (pair pith:neo lore:neo))
^- [(set reaction) tape]
=/ meta=(pair pith:neo lore:neo) (~(got by deps) %src)
=/ uvase=(unit vase) ::(get-vase-saga-by-pith:su q.meta /)
=/ idea=(unit idea:neo) (~(get of:neo q.meta) /)
?~ idea ~
`q.q.saga:(need idea)
=/ here (en-tape:pith:neo p:(~(got by deps) %src))
?~ uvase `here
:- !<((set reaction) (need uvase))
here
::
++ sort-reactions
|= reactions=(list reaction)
^- (list [reaction=@t num=@ud data=(list reaction)])
%- sort
:_ aor
%~ tap in
%- silt
%+ turn reactions
|= r=reaction
^- [@t [@ud (list reaction)]]
=/ match
%+ skim reactions
|= b=reaction
=(reaction.r reaction.b)
[reaction.r [(lent match) match]]
--

View File

@ -123,6 +123,7 @@
++ strategy-change-cards
|= jon=json
^- (list card:neo)
~& jon
=/ here
%- pave:neo
%- (ot ~[here+pa]):dejs:format

View File

@ -0,0 +1,277 @@
/@ ui-event
/@ timeline-diff
/- feather-icons
/- serv=sky-server
/- su=shrub-utils
/- fp=feed-parser
^- kook:neo
=<
|%
++ state pro/%manx
++ poke (sy %ui-event %rely ~)
++ kids
*kids:neo
++ deps
%- ~(gas by *band:neo)
:~ :- %src
:- req=&
:- [pro/%timeline (sy %timeline-diff ~)]
:+ ~ %z
%- ~(gas by *lads:neo)
:~ :- [|/%p |]
[[%only %sig] ~]
:- [|/%p |/%da |]
[[%only %post] ~]
==
==
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
::
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
=/ =lore:neo q:(~(got by deps.bowl) %src)
[~ manx/!>((render lore bowl))]
::
++ poke
|= [=stud:neo =vase]
^- (quip card:neo pail:neo)
::?=(%ui-event stud)
?+ stud ~|(bad-stud/stud !!)
%ui-event
=/ event !<(ui-event vase)
?> ?=([%submit %make-post ~] path.event)
=/ here p:(~(got by deps.bowl) %src)
=/ =cord (~(got by data.event) 'post')
=/ renderer=pith /blue/post-link-ui
=/ pith /[p/our.bowl]/posts/[da/now.bowl]
=/ quote-post-piths (get-pith:fp cord)
:_ pail
?~ quote-post-piths
:~ [here %poke [%timeline-diff !>([%post [renderer pith]])]]
[pith %make %txt `txt/!>(cord) ~]
==
:~ [here %poke [%timeline-diff !>([%make-post cord])]]
==
%rely
=/ =lore:neo q:(~(got by deps.bowl) %src)
[~ manx/!>((render lore bowl))]
==
--
--
::
|%
++ render
|_ [=lore:neo =bowl:neo]
++ $
^- manx
;html
;head
;* old-standard-head-tags:serv
;* standard-head-tags:serv
;+ script
==
;body
;+ main
==
==
++ main
^- manx
;main.p-page.mw-page.ma.fc.g2
=id "0"
;+ make-post
;+ feed-switch
;+ feed
==
::
++ script
;script
=defer ""
;+ ;/ %- trip
'''
function resizeIframe(obj) {
let scrollHeight = obj.contentWindow.document.documentElement.scrollHeight;
if (scrollHeight > 300) {
obj.style.height = '300px';
} else {
obj.style.height = scrollHeight + 2 + 'px';
}
};
function receiveMessage(event) {
if (event.origin === window.location.origin){
if(event.data.messagetype === 'new-wind'){
window.parent.postMessage(event.data, window.location.origin)
}
}else{
return;
}
}
window.addEventListener('message', receiveMessage, false);
'''
==
::
++ make-post
;form.fr.jc.g2.p2
=event "/submit/make-post"
;textarea.p3.bd1.br1.grow
=style "min-height:10em"
=type "text"
=placeholder "Start your post here"
=name "post"
=oninput "this.setAttribute('value', this.value)"
=required ""
=autocomplete "off"
;
==
;button.loader.p1.bd1.br1.b1.hf.hover
=style "align-self: end;"
=type "submit"
;span.loaded: post
;span.loading
;+ loading.feather-icons
==
==
==
::
++ feed-switch
;div.fr.jc.g2.p2
;button.loader.p2.br1.b1.hover
=onclick
"""
document.getElementById('all').classList.remove('hidden');
document.getElementById('followed').classList.add('hidden');
document.getElementById('published').classList.add('hidden');
"""
;span.loaded: all
;span.loading
;+ loading.feather-icons
==
==
;button.loader.p2.br1.b1.hover
=onclick
"""
document.getElementById('followed').classList.remove('hidden');
document.getElementById('all').classList.add('hidden');
document.getElementById('published').classList.add('hidden');
"""
;span.loaded: followed
;span.loading
;+ loading.feather-icons
==
==
;button.loader.p2.br1.b1.hover
=onclick
"""
document.getElementById('published').classList.remove('hidden');
document.getElementById('all').classList.add('hidden');
document.getElementById('followed').classList.add('hidden');
"""
;span.loaded: published
;span.loading
;+ loading.feather-icons
==
==
==
::
++ feed
;div
;div#all
;+ (show-feed (get-all-feed-entries lore))
==
;div#published.hidden
;+ (show-feed (get-my-feed-entries lore our.bowl))
==
;div#followed.hidden
;+ (show-feed (get-follow-feed lore))
==
==
::
++ show-feed
|= kids=(list pith)
=/ sorted-posts (sort-by-date kids)
^- manx
;div.fc.g2
;*
%+ turn sorted-posts
|= =pith:neo
=/ idea=idea:neo (~(got of:neo lore) pith)
=/ post !<([renderer=pith:neo pith=pith:neo] q.q.saga.idea)
=/ post-date ;; @da +:(rear pith)
;div.wf.fc
;div.fr.jb
;p.p1: {(tail (en-tape:pith:neo /[(head pith.post)]))}
;p: {(pretty-date post-date bowl)}
==
;iframe.wf.bd2.post.br2.b2.grow
=style "max-height: 300px; overflow: auto; border-color: var(--b0)"
=onload "resizeIframe(this)"
=src (en-tape:pith:neo (welp renderer.post pith.post))
;
==
;imp_mast-meta-reaction: {(en-tape:pith:neo (welp /[p/our.bowl]/storage/reactions/[p/our.bowl]/home/feed pith))}
;imp_mast-meta-comment: {(en-tape:pith:neo (welp /[p/our.bowl]/storage/comments/[p/our.bowl]/home/feed pith))}
==
==
::
++ sort-by-date
|= kids=(list pith)
%+ sort kids
|= [a=pith b=pith]
(gth ->:(tail a) ->:(tail b))
::
--
::
++ pretty-date
|= [date=@da =bowl:neo]
^- tape
=/ d (yore date)
=/ months
^- (list tape)
:~
"Jan"
"Feb"
"Mar"
"Apr"
"May"
"Jun"
"Jul"
"Aug"
"Sep"
"Oct"
"Nov"
"Dec"
==
?: &(=(m:d m:(yore now.bowl)) =(d:t:d d:t:(yore now.bowl)))
"{(y-co:co h:t:d)}:{(y-co:co m:t:d)}"
"{(y-co:co h:t:d)}:{(y-co:co m:t:d)} {(snag (dec m:d) months)}{(y-co:co d:t:d)}"
::
++ get-all-feed-entries
|= =lore:neo
^- (list pith)
%+ skim (kidz-at-pith:su / lore)
|= =pith
(gth (lent pith) 1)
::
::
++ get-my-feed-entries
|= [=lore:neo our=ship]
^- (list pith)
(kidz-at-pith:su /[p/our] lore)
::
++ get-follow-feed
|= =lore:neo
^- (list pith)
=/ followed=(set @p)
::(got-vase-saga-by-pith:su lore /)
=/ idea=idea:neo (~(got of:neo lore) /)
!<((set @p) q.q.saga:idea)
%- zing
%+ turn ~(tap in followed)
|= ship=@p
%+ turn
(kids-at-pith:su lore /[p/ship])
|= =pith
(welp /[p/ship] pith)
::
--

View File

@ -0,0 +1,328 @@
/@ txt
/- serv=sky-server
/- feather-icons
/- manx-utils
/- su=shrub-utils
/- fp=feed-parser
^- kook:neo
=<
|%
++ state pro/%eyre-task
++ poke (sy %rely %iris-res ~)
++ kids *kids:neo
++ deps
%- ~(gas by *band:neo)
:~ :- %src
:- req=&
:- [[%only %txt] ~]
~
==
++ form
|_ [=bowl:neo =aeon:neo =pail:neo]
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
=/ task !<(task:eyre:neo q.pail)
?+ stud !!
%iris-res
::
:: XX maybe fetching of url metadata should be done before initiating iframe, perhaps fetching on post ?
:: creates ugly UI where iframe sized before url metadata is fetched
::
=+ !<(=res:iris:neo vax)
?. ?=(%finished -.dat.res)
[~ pail]
?~ full-file.dat.res
[~ pail]
=/ body=cord q.data.u.full-file.dat.res
=/ title ~(title body-parser:fp body)
=/ meta-map ~(metadata body-parser:fp body)
=/ meta-data=manx (meta-div meta-map title)
:_ pail
(eyre-cards [bowl task meta-data])
::
%rely
:_ pail
(eyre-cards [bowl task *manx])
==
::
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
=/ [=stud:neo =vase] (need pal)
=+ !<(=task:eyre:neo vase)
=/ [eyre-id=@ta req=inbound-request:eyre] task
?+ method.request.req ~|(%unsupported-http-method !!)
%'GET'
:_ [stud vase]
(eyre-cards [bowl task *manx])
::
%'POST'
=/ here p:(~(got by deps.bowl) %src)
=/ body (parse-body:serv request.req)
=/ mu ~(. manx-utils body)
=/ head (@tas (got:mu %head))
?+ head !!
%get-metadata
=/ url (got:mu %value)
=/ =request:http
:* %'GET'
url
['Accept'^'application/json' ~]
~
==
=/ =req:iris:neo [here.bowl request]
:_ [stud vase]
:~
[#/[p/our.bowl]/$/iris %poke iris-req/!>(req)]
==
==
::
==
--
--
::
|%
++ eyre-cards
|= [=bowl:neo [eyre-id=@ta req=inbound-request:eyre] max=manx]
=/ data=sign:eyre:neo [eyre-id %data `(manx-to-octs max)]
=+ #/[p/our.bowl]/$/eyre
:~ (head-card - eyre-id)
::
?: =(*manx max)
:* -
%poke
%eyre-sign
!>
:+ eyre-id
%data
:- ~
%- manx-to-octs
%~ render
web
:- bowl
(pave:neo pax:(parse-url-frfr:serv request.req))
==
[- %poke eyre-sign/!>(data)]
::
(done-card - eyre-id)
[here.bowl %cull ~]
[here.bowl %tomb ~]
==
::
::
++ head-card
|= [=pith eyre-id=@ta]
:* pith
%poke
%eyre-sign
!>
:^ eyre-id
%head
200
['content-type' 'text/html']~
==
::
++ done-card
|= [=pith eyre-id=@ta]
[pith %poke eyre-sign/!>([eyre-id %done ~])]
::
++ manx-to-octs
|= man=manx
(as-octt:mimes:html (en-xml:html man))
::
++ web
|_ [=bowl:neo name=pith]
++ render
^- manx
;html.hfc
;head
;* old-standard-head-tags:serv
;* standard-head-tags:serv
==
;body.b2.hfc
=style "min-height: unset;"
=hx-ext "dom-enc"
;main.ma.fc.g1
;+ post-txt
==
==
==
++ post-txt
=/ =lore:neo q:(~(got by deps.bowl) %src)
=/ idea=idea:neo (~(got of:neo lore) /)
=/ txt !<(txt q.q.saga.idea)
=/ text=tape (trip txt)
=/ parsed=[url=(unit tape) txt=tape]
(get-url:fp text)
?~ url.parsed (url-renderer %txt url.parsed text)
=/ url (need url.parsed)
=/ type=@tas (url-parser:fp url)
(url-renderer type url txt.parsed)
::
++ url-renderer
|_ [type=@tas url=tape text=tape]
++ $
?+ type fetch-metadata
%txt txt-renderer
%mp3 mp3-renderer
%mp4 mp4-renderer
%png img-renderer
%jpg img-renderer
%gif img-renderer
==
::
++ fetch-metadata
;div.fc.as.p2.g1.hf.wf
;div
;+
?: =("" text) ;div;
;p.grow.p2: {text}
==
;a.b4.br1.p2.wf
=style "margin-bottom: 0.5rem;"
=href url
=target "_blank"
;div
=hx-post (en-tape:pith:neo name)
=head "get-metadata"
=hx-trigger "load"
=value url
=hx-swap "innerHTML"
;
==
;p.s-1.mono.f2.p1
=style "overflow-wrap: break-word;"
; {url}
==
==
==
::
++ txt-renderer
;div.hfc.fc.as.p4.wf
;p.grow: {text}
==
::
++ mp3-renderer
;div.wf.hf.fc.as.p2.g1
=style "overflow: auto; font-size: calc(1rem + (300px - 1em) / 100);"
;p.grow.p2: {text}
;audio
=controls ""
;source
=src url
=type "audio/mpeg"
;
==
;span: not supported
==
==
::
++ mp4-renderer
;div.wf.hf.fc.as.p2.g1
=style "overflow: auto; font-size: calc(1rem + (300px - 1em) / 100);"
;p.grow.p2: {text}
;video.wf
=height "230"
=controls ""
;source
=src url
=type "video/mp4"
;
==
;span: not supported
==
==
::
++ img-renderer
;div.hf.fc.ac.p2.g1
=style "overflow: auto; font-size: calc(1rem + (300px - 1em) / 100);"
;div.fc.as.wf
;p.grow.p2: {text}
==
;div.fr.jc.g1
;img.grow
=style "max-height: 230px"
=src url
;
==
==
==
--
--
::
++ meta-div
|= [meta-map=(map @tas tape) title=tape]
=/ meta ~(. by meta-map)
=/ img-style
"""
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
object-fit: cover
"""
=/ img-wrap
?: &(=(~ (get:meta %description)) =(~ (get:meta %'og:description')) =(~ (get:meta %'twitter:description')))
"""
width: 80px;
height: 80px;
overflow: hidden;
position: relative;
"""
"""
width: 150px;
height: 150px;
overflow: hidden;
position: relative;
"""
^- manx
;div.wf.fr.g1
;+
?: &(=(~ (get:meta %'og:image')) =(~ (get:meta %'twitter:image')))
;div;
?. =(~ (get:meta %'og:image'))
;div
=style img-wrap
;img.p1
=style img-style
=src (got:meta %'og:image')
;
==
==
;div
=style img-wrap
;img.p1
=style img-style
=src (got:meta %'twitter:image')
;
==
==
;div.fc
=style "flex: 1;"
;+
?: &(=("" title) =(~ (get:meta %'og:title')) =("" (get:meta %'twitter:title')))
;div;
?. =("" title)
;p.bold.p1: {title}
?. =(~ (get:meta %'og:title'))
;p.bold.p1: {(got:meta %'og:title')}
;p.bold.p1: {(got:meta %'twitter:title')}
;+
?: &(=(~ (get:meta %description)) =(~ (get:meta %'og:description')) =(~ (get:meta %'twitter:description')))
;div;
?. =(~ (get:meta %description))
;p.s-1.p1: {(length (got:meta %description))}
?. =(~ (get:meta %'og:description'))
;p.s-1.p1: {(length (got:meta %'og:description'))}
;p.s-1.p1: {(length (got:meta %'twitter:description'))}
==
==
::
++ length
|= =tape
?. (gth (lent tape) 300) tape
(welp (oust [360 (sub (lent tape) 300)] tape) "...")
--

View File

@ -0,0 +1,160 @@
/@ quote-post
/@ post
/- serv=sky-server
/- feather-icons
/- manx-utils
/- su=shrub-utils
/- fp=feed-parser
^- kook:neo
=<
|%
++ state pro/%eyre-task
++ poke (sy %rely ~)
++ kids *kids:neo
++ deps
%- ~(gas by *band:neo)
:~ :- %src
:- req=&
:- [[%only %quote-post] ~]
~
==
++ form
|_ [=bowl:neo =aeon:neo =pail:neo]
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
=/ task !<(task:eyre:neo q.pail)
?< =(%rely stud)
:_ pail
(eyre-cards [bowl task])
::
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
=/ [=stud:neo =vase] (need pal)
=+ !<(=task:eyre:neo vase)
=/ [eyre-id=@ta req=inbound-request:eyre] task
?+ method.request.req ~|(%unsupported-http-method !!)
%'GET'
:_ [stud vase]
(eyre-cards [bowl task])
==
--
--
::
|%
++ eyre-cards
|= [=bowl:neo [eyre-id=@ta req=inbound-request:eyre]]
=+ #/[p/our.bowl]/$/eyre
:~ (head-card - eyre-id)
::
:* -
%poke
%eyre-sign
!>
:+ eyre-id
%data
:- ~
%- manx-to-octs
%~ render
web
:- bowl
(pave:neo pax:(parse-url-frfr:serv request.req))
==
::
(done-card - eyre-id)
[here.bowl %cull ~]
[here.bowl %tomb ~]
==
::
::
++ head-card
|= [=pith eyre-id=@ta]
:* pith
%poke
%eyre-sign
!>
:^ eyre-id
%head
200
['content-type' 'text/html']~
==
::
++ done-card
|= [=pith eyre-id=@ta]
[pith %poke eyre-sign/!>([eyre-id %done ~])]
::
++ manx-to-octs
|= man=manx
(as-octt:mimes:html (en-xml:html man))
::
++ web
|_ [=bowl:neo name=pith]
++ render
^- manx
;html.hfc
=style "overflow: hidden;"
;head
;* old-standard-head-tags:serv
;* standard-head-tags:serv
;+ script
==
;body.b2.hfc
=style "min-height: unset;"
=hx-ext "dom-enc"
;main.ma.fc.g1
;+ render-post
==
==
==
++ script
;script
;+ ;/ %- trip
'''
function resizeIframe(obj) {
let scrollHeight = obj.contentWindow.document.documentElement.scrollHeight;
if (scrollHeight > 230) {
obj.style.height = '230px';
} else {
obj.style.height = scrollHeight + 2 + 'px';
}
}
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('[target]').forEach(element => {
element.addEventListener('click', (event) => {
event.preventDefault();
if (event.currentTarget.getAttribute('target') === 'sky') {
let message = event.currentTarget.getAttribute('href')
let messageObj = {
messagetype: 'new-wind',
href: message
};
window.parent.postMessage(messageObj, window.location.origin)
}
});
});
});
'''
==
++ render-post
=/ =lore:neo q:(~(got by deps.bowl) %src)
=/ idea=idea:neo (~(got of:neo lore) /)
=/ quote-post !<(quote-post q.q.saga.idea)
=/ p :(weld "<p>" (hypertext:fp -.quote-post) "</p>")
=/ text (tail (de-xml:html (crip p)))
=/ posts=(list post) +.quote-post
;div.fc.p2.g1
;+ text
;div.fc.ac.p2.g2
;*
%+ turn posts
|= p=post
;iframe.wf.bd2.post.br2.b2.grow
=onload "resizeIframe(this)"
=src (en-tape:pith:neo (welp renderer.p pith.p))
;
==
==
==
--
--

View File

@ -0,0 +1,42 @@
/@ post
/@ timeline-diff
::
^- kook:neo
|%
++ state pro/%sig
++ poke (sy %post ~)
++ kids
:+ ~ %y
%- ~(gas by *lads:neo)
:~ :- [|/%da |]
[pro/%post ~]
==
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo state=pail:neo]
++ init
|= old=(unit pail:neo)
^- (quip card:neo pail:neo)
[~ sig/!>(~)]
::
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> =(our ship.src):bowl
:_ state
?+ stud !!
%post
=/ post-pith (welp here.bowl ~[da/now.bowl])
~& > post-pith/post-pith
=/ diff !<(timeline-diff vax)
?> ?=(%post -.diff)
:~
:: [/[p/our.bowl]/storage %poke storage-diff/!>([(welp /comments post-pith) [%comment ~]])]
:: [/[p/our.bowl]/storage %poke storage-diff/!>([(welp /reactions post-pith) [%reaction ~]])]
:- post-pith
[%make %post `post/!>(+.diff) ~]
==
==
--
--

View File

@ -0,0 +1,50 @@
/@ post
^- kook:neo
|%
++ state pro/%sig
++ poke (silt %rely ~)
++ kids
:+ ~ %y
%- ~(gas by *lads:neo)
:~ :- [|/%da |]
[pro/%post ~]
==
++ deps
%- ~(gas by *deps:neo)
:~ :- %pub
:+ req=| [pro/%sig (sy %post ~)]
:+ ~ %y
%- ~(gas by *lads:neo)
:~ :- [|/%da |]
[pro/%post ~]
==
==
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo state=pail:neo]
++ init
|= old=(unit pail:neo)
^- (quip card:neo pail:neo)
:: ~& >> p:(~(got by deps.bowl) %pub)
:: ~& >> (kids-at-pith:su q:(~(got by deps.bowl) %pub) /)
[~ sig/!>(~)]
::
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> =(%rely stud)
~& >> 'got rely'
:_ state
%+ murn
~(tap of:neo q:(~(got by deps.bowl) %pub))
|= [=pith:neo =idea:neo]
^- (unit card:neo)
?. ?=([[%da @] ~] pith)
~
?: (~(has of:neo kids.bowl) pith)
~
?. =(%post p.pail.idea)
~
`[(welp here.bowl pith) %make %post `pail.idea ~]
--
--

View File

@ -0,0 +1 @@
~

View File

@ -0,0 +1 @@
~

View File

@ -0,0 +1,44 @@
/@ reaction
/@ meta-social
^- kook:neo
|%
++ state pro/%reactions ::(set reaction)
++ poke (sy %meta-social ~)
++ kids
:+ ~ %y
%- ~(gas by *lads:neo)
:~ :- &
[pro/%reactions (sy %meta-social ~)]
==
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
:- ~
?~ pal
reactions/!>(~)
=+ !<(=meta-social q:(need pal))
?> ?=(%reaction -.meta-social)
reactions/!>(+.meta-social)
::
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> ?=(%meta-social stud)
=/ state !<((set reaction) q.pail)
=/ diff !<(meta-social vax)
?> ?=(%reaction -.diff)
=/ new=(set reaction) +.diff
=/ new-state=(set reaction)
?~ new state
=/ has-in !=(~ (~(dig in state) -.new))
?: has-in
%- ~(del in state) -.new
%- ~(put in state) -.new
:_ reactions/!>(new-state)
~
--
--

View File

@ -0,0 +1,39 @@
/@ storage
/@ storage-diff
/@ meta-social
/- su=shrub-utils
^- kook:neo
|%
++ state pro/%storage
++ poke (sy %storage-diff ~) ::[to=pith:neo poke=meta-social]
++ kids
:+ ~ %z
%- ~(gas by *lads:neo)
:~ :- [|/%tas |/%p &]
[[%any ~] (sy %meta-social ~)]
==
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =aeon:neo =pail:neo]
++ init
|= pal=(unit pail:neo)
^- (quip card:neo pail:neo)
[~ storage/!>(~)]
::
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
?> ?=(%storage-diff stud)
:_ storage/!>(~)
=/ diff !<(storage-diff vax)
?~ (find [to.diff ~] (kidz-at-pith:su / kids.bowl))
?> ?=(@ -.to.diff)
=/ make-stud ;; stud:neo -.to.diff
~& > [making-in-storage/make-stud pith/(welp here.bowl to.diff)]
:~ [(welp here.bowl to.diff) %make make-stud `[make-stud !>(poke.diff)] ~]
==
:~ [(welp here.bowl to.diff) %poke %meta-social !>(poke.diff)]
==
--
--

View File

@ -0,0 +1,113 @@
/@ timeline
/@ timeline-diff
/@ post
/- fp=feed-parser
=>
::
|%
++ make-sub
|= [here=pith =ship]
^- (list card:neo)
=/ dep
(malt ~[[%pub ~[p/ship %home %feed p/ship]]])
:~ :- (welp here ~[p/ship])
[%make %post-sub ~ dep]
==
--
::
|%
++ state pro/%timeline
++ poke
(sy %timeline-diff ~)
++ kids
:+ ~ %y :: XX can I make this a %z that requires grandkids = posts?
%- ~(gas by *lads:neo)
:~ :- [|/%p |]
[pro/%sig ~]
==
:: /[p/our]/sky/strategy/[p/our]
++ deps
%- ~(gas by *band:neo)
:~ :- %src
^- fief:neo
:- req=&
^- quay:neo
:- [pro/%order ~]
^- (unit port:neo)
:+ ~ %z
%- ~(gas by *lads:neo)
:~ :- &
`lash:neo`[pro/%order ~]
==
==
++ form
|_ [=bowl:neo =aeon:neo state=pail:neo]
++ init
|= old=(unit pail:neo)
^- (quip card:neo pail:neo)
:_ timeline/!>((sy our.bowl ~))
:: post-pub for our posts
:~ :- (welp here.bowl ~[p/our.bowl])
[%make %post-pub ~ ~]
:- (welp #/[p/our.bowl]/sky/strategy here.bowl)
[%make %order `order/!>([`pith`#/mast/mast-timeline-ui ~]) ~]
==
::
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo pail:neo)
=/ following !<(timeline q.state)
::?+ stud !!
:: %timeline-diff
?> =(%timeline-diff stud)
=/ poke !<(timeline-diff vax)
?- -.poke
:: XX if you unfollow and refollow, what happens?
:: if you make over a sub, do the kids get remade?
%follow
:- (make-sub [here.bowl ship.poke])
timeline/!>((~(put in following) ship.poke))
::
%unfollow
:- ~
timeline/!>((~(del in following) ship.poke))
::
%hear :: other shrubs should poke this liberally
:- (make-sub [here.bowl ship.poke])
state
::
%post
=/ meta-pith (welp here.bowl /[p/our.bowl]/[da/now.bowl])
~& > meta-pith/meta-pith
:_ state
:~ :- (welp here.bowl ~[p/our.bowl])
[%poke post/!>([%post post.poke])]
[/[p/our.bowl]/storage %poke storage-diff/!>([(welp /comments meta-pith) [%comment ~]])]
[/[p/our.bowl]/storage %poke storage-diff/!>([(welp /reactions meta-pith) [%reaction ~]])]
==
::
%make-post
=/ piths=(list pith) (get-pith:fp +.poke)
=/ =lore:neo q:(~(got by deps.bowl) %src)
=/ posts=(list post)
%+ turn piths
|= pit=pith
=/ u-idea=(unit idea:neo) (~(get of:neo lore) (oust [0 1] pit))
::
:: XX for now default renderer will be /tree
::
?~ u-idea [/tree pit]
=/ order
!<((list pith:neo) q.pail:(need u-idea))
[(head order) pit]
~& > posts/posts
=/ pith /[p/our.bowl]/posts/[da/now.bowl]
:_ state
:~
[pith %make %quote-post `quote-post/!>([+.poke posts]) ~]
:- (welp here.bowl ~[p/our.bowl])
[%poke post/!>([%post `post`[/blue/post-pith-ui pith]])]
==
==
--
--

View File

@ -0,0 +1,158 @@
/- su=shrub-utils
|%
++ body-parser
|_ [body=cord]
::
++ title
^- tape
=/ title=(unit manx) get-title
?~ title ""
v:(head a.g:(head c:(need title)))
::
++ get-title :: get's only title
^- (unit manx)
=/ tag "<title>"
?~ (fand tag (trip body)) ~
=/ ix-start=@ud (head (fand tag (trip body)))
=/ half-way (oust [0 ix-start] (trip body))
=/ close-tag=tape (into tag 1 '/')
=/ lent-tag (lent close-tag)
=/ ix-end=@ud (add lent-tag (head (fand close-tag half-way)))
%- de-xml:html
%- crip
%+ oust [ix-end (sub (lent half-way) ix-end)]
half-way
::
++ metadata
^- (map @tas tape)
=/ ix-start=(list @ud) (fand "<meta" (trip body))
%- malt
%+ skip
%+ turn ix-start
|= ix=@ud
=/ pair (meta-tag ix)
pair
|= pair=[@tas tape]
=(%$ -.pair)
::
++ meta-tag
|= ix-start=@ud
^- [@tas tape]
=/ half-way (oust [0 ix-start] (trip body))
=/ ix-end=@ud +((head (fand ">" half-way)))
=/ xml=(unit manx)
%- de-xml:html
%- crip
%- close-meta
%- clean-meta
%+ oust [ix-end (sub (lent half-way) ix-end)]
half-way
?~ xml [%$ ""]
=/ manx-map (malt a.g:(need xml))
=/ name (parse-prop (~(get by manx-map) %name))
=/ prop (parse-prop (~(get by manx-map) %property))
?: &(=(~ name) =(~ prop)) [%$ ""]
?~ name
[(need prop) `tape`(~(got by manx-map) %content)]
[(need name) `tape`(~(got by manx-map) %content)]
::
++ parse-prop
|= u-tape=(unit tape)
%+ rust
;; tape
?~ u-tape ~
(need u-tape)
(perk ~[%'og:title' %'og:description' %'og:image' %description %'twitter:title' %'twitter:description' %'twitter:image'])
::
++ clean-meta
|= meta=tape
^- tape
=/ =wall
%+ turn
;; wall (scan meta ;~(plug (more pam (star ;~(pose (shim 31 37) (shim 39 255) gaq)))))
|= tap=tape
;; tape
%- zing
(scan tap (more gaq (star (shim 31 255))))
;; tape (zing wall)
::
:: closing meta-tag
::
++ close-meta
|= meta=tape
=/ ix (sub (lent meta) 2)
?: =('/' (snag ix meta)) meta
(into meta +(ix) '/')
--
++ url-parser
|= =tape
;; @tas
%- crip
(oust [0 (sub (lent tape) 3)] tape)
::
++ txt-to-words
|= text=tape
^- (list tape)
=/ =wall
;; wall
%+ scan text
;~ plug
%+ more ace
(star ;~(pose (shim 33 255) (just `@`10)))
==
::
::~& > wall
::
=/ words
;; (list tape)
%- zing
%+ turn wall
|= t=tape
;; (list tape)
(scan t ;~(plug (more gaq (star ;~(pose (shim 33 255))))))
words
::
++ get-url
|= text=tape
^- [url=(unit tape) txt=tape]
=/ words (txt-to-words text)
::
:: XX add logic for adding '/0a' spaces back into tape
::
=/ skid-url
%+ skid words
|= t=tape
=(~ (de-purl:html (crip t)))
::
:: XX for now takes only first url out of text
::
=/ txt=tape (zing (join " " p.skid-url))
?~ q.skid-url `txt
[(some (head q.skid-url)) txt]
::
++ get-pith
|= =cord
^- (list pith)
=/ words (txt-to-words (trip cord))
:: ~& > words/words
=/ piths=(list tape)
%+ skip words
|= t=tape
=(~ (rust t stap))
:: ~& >> piths/piths
%+ turn piths
|= =tape
~& >>> (en-pith:su (crip tape))
(en-pith:su (crip tape))
::
++ hypertext
|= =cord
^- tape
=/ words (txt-to-words (trip cord))
=/ a-text=(list tape)
%+ turn words
|= t=tape
?~ (rust t stap) t
"<a href='{t}' target='sky' style='color: white;' class='hover'>{t}</a>"
;; tape (zing (join " " a-text))
--

View File

@ -0,0 +1 @@
,[when=@da from=@p txt=@t]

View File

@ -0,0 +1,6 @@
/@ comment
/@ reaction
$% [%comment (set comment)]
[%reaction (set reaction)]
[%tags (set @tas)]
==

View File

@ -0,0 +1 @@
,[renderer=pith =pith]

View File

@ -0,0 +1,3 @@
/@ post
/@ txt
,[=txt =(list post)]

View File

@ -0,0 +1 @@
,[from=@p reaction=@t]

View File

@ -0,0 +1,4 @@
/@ meta-social
$%
[to=pith:neo poke=meta-social]
==

View File

@ -0,0 +1 @@
,~

View File

@ -0,0 +1,8 @@
/@ post
/@ txt
$% [%follow =ship]
[%unfollow =ship]
[%hear =ship]
[%post =post]
[%make-post =txt]
==

View File

@ -0,0 +1 @@
,(set @p)