mirror of
https://github.com/urbit/shrub.git
synced 2024-10-26 21:09:47 +03:00
messenger-created
This commit is contained in:
commit
c9ad8ca9a3
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
});
|
||||
)
|
||||
|
45
pkg/arvo/neo/cod/std/src/imp/comments.hoon
Normal file
45
pkg/arvo/neo/cod/std/src/imp/comments.hoon
Normal 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)
|
||||
~
|
||||
--
|
||||
--
|
@ -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]
|
||||
==
|
||||
|
197
pkg/arvo/neo/cod/std/src/imp/mast-meta-comment.hoon
Normal file
197
pkg/arvo/neo/cod/std/src/imp/mast-meta-comment.hoon
Normal 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)}"
|
||||
--
|
179
pkg/arvo/neo/cod/std/src/imp/mast-meta-reaction.hoon
Normal file
179
pkg/arvo/neo/cod/std/src/imp/mast-meta-reaction.hoon
Normal 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]]
|
||||
--
|
@ -123,6 +123,7 @@
|
||||
++ strategy-change-cards
|
||||
|= jon=json
|
||||
^- (list card:neo)
|
||||
~& jon
|
||||
=/ here
|
||||
%- pave:neo
|
||||
%- (ot ~[here+pa]):dejs:format
|
||||
|
277
pkg/arvo/neo/cod/std/src/imp/mast-timeline-ui.hoon
Normal file
277
pkg/arvo/neo/cod/std/src/imp/mast-timeline-ui.hoon
Normal 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)
|
||||
::
|
||||
--
|
328
pkg/arvo/neo/cod/std/src/imp/post-link-ui.hoon
Normal file
328
pkg/arvo/neo/cod/std/src/imp/post-link-ui.hoon
Normal 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) "...")
|
||||
--
|
160
pkg/arvo/neo/cod/std/src/imp/post-pith-ui.hoon
Normal file
160
pkg/arvo/neo/cod/std/src/imp/post-pith-ui.hoon
Normal 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))
|
||||
;
|
||||
==
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
42
pkg/arvo/neo/cod/std/src/imp/post-pub.hoon
Normal file
42
pkg/arvo/neo/cod/std/src/imp/post-pub.hoon
Normal 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) ~]
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
50
pkg/arvo/neo/cod/std/src/imp/post-sub.hoon
Normal file
50
pkg/arvo/neo/cod/std/src/imp/post-sub.hoon
Normal 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 ~]
|
||||
--
|
||||
--
|
1
pkg/arvo/neo/cod/std/src/imp/post.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/imp/post.hoon
Normal file
@ -0,0 +1 @@
|
||||
~
|
1
pkg/arvo/neo/cod/std/src/imp/quote-post.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/imp/quote-post.hoon
Normal file
@ -0,0 +1 @@
|
||||
~
|
44
pkg/arvo/neo/cod/std/src/imp/reactions.hoon
Normal file
44
pkg/arvo/neo/cod/std/src/imp/reactions.hoon
Normal 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)
|
||||
~
|
||||
--
|
||||
--
|
39
pkg/arvo/neo/cod/std/src/imp/storage.hoon
Normal file
39
pkg/arvo/neo/cod/std/src/imp/storage.hoon
Normal 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)]
|
||||
==
|
||||
--
|
||||
--
|
113
pkg/arvo/neo/cod/std/src/imp/timeline.hoon
Normal file
113
pkg/arvo/neo/cod/std/src/imp/timeline.hoon
Normal 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]])]
|
||||
==
|
||||
==
|
||||
--
|
||||
--
|
158
pkg/arvo/neo/cod/std/src/lib/feed-parser.hoon
Normal file
158
pkg/arvo/neo/cod/std/src/lib/feed-parser.hoon
Normal 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))
|
||||
--
|
1
pkg/arvo/neo/cod/std/src/pro/comment.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/comment.hoon
Normal file
@ -0,0 +1 @@
|
||||
,[when=@da from=@p txt=@t]
|
6
pkg/arvo/neo/cod/std/src/pro/meta-social.hoon
Normal file
6
pkg/arvo/neo/cod/std/src/pro/meta-social.hoon
Normal file
@ -0,0 +1,6 @@
|
||||
/@ comment
|
||||
/@ reaction
|
||||
$% [%comment (set comment)]
|
||||
[%reaction (set reaction)]
|
||||
[%tags (set @tas)]
|
||||
==
|
1
pkg/arvo/neo/cod/std/src/pro/post.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/post.hoon
Normal file
@ -0,0 +1 @@
|
||||
,[renderer=pith =pith]
|
3
pkg/arvo/neo/cod/std/src/pro/quote-post.hoon
Normal file
3
pkg/arvo/neo/cod/std/src/pro/quote-post.hoon
Normal file
@ -0,0 +1,3 @@
|
||||
/@ post
|
||||
/@ txt
|
||||
,[=txt =(list post)]
|
1
pkg/arvo/neo/cod/std/src/pro/reaction.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/reaction.hoon
Normal file
@ -0,0 +1 @@
|
||||
,[from=@p reaction=@t]
|
4
pkg/arvo/neo/cod/std/src/pro/storage-diff.hoon
Normal file
4
pkg/arvo/neo/cod/std/src/pro/storage-diff.hoon
Normal file
@ -0,0 +1,4 @@
|
||||
/@ meta-social
|
||||
$%
|
||||
[to=pith:neo poke=meta-social]
|
||||
==
|
1
pkg/arvo/neo/cod/std/src/pro/storage.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/storage.hoon
Normal file
@ -0,0 +1 @@
|
||||
,~
|
8
pkg/arvo/neo/cod/std/src/pro/timeline-diff.hoon
Normal file
8
pkg/arvo/neo/cod/std/src/pro/timeline-diff.hoon
Normal file
@ -0,0 +1,8 @@
|
||||
/@ post
|
||||
/@ txt
|
||||
$% [%follow =ship]
|
||||
[%unfollow =ship]
|
||||
[%hear =ship]
|
||||
[%post =post]
|
||||
[%make-post =txt]
|
||||
==
|
1
pkg/arvo/neo/cod/std/src/pro/timeline.hoon
Normal file
1
pkg/arvo/neo/cod/std/src/pro/timeline.hoon
Normal file
@ -0,0 +1 @@
|
||||
,(set @p)
|
Loading…
Reference in New Issue
Block a user