From a9cbd14b3bf36debd54c8d374cbf6060e8486dae Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 21 Jun 2025 21:36:59 +0500 Subject: [PATCH 01/21] add boilerplate component --- bundle.js | 761 ++++++++++++++++-- src/node_modules/steps_wizard/steps_wizard.js | 80 +- .../steps_wizard/steps_wizard.json | 5 + src/node_modules/steps_wizard/stepswizard.css | 106 +++ web/page.js | 8 + 5 files changed, 895 insertions(+), 65 deletions(-) create mode 100644 src/node_modules/steps_wizard/steps_wizard.json create mode 100644 src/node_modules/steps_wizard/stepswizard.css diff --git a/bundle.js b/bundle.js index 4b71c27..1f71bb8 100644 --- a/bundle.js +++ b/bundle.js @@ -67,9 +67,7 @@ async function action_bar(opts, protocol) { function fail (data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject(data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function iconject(data) { @@ -180,7 +178,7 @@ function fallback_module() { } } }).call(this)}).call(this,"/src/node_modules/action_bar/action_bar.js") -},{"STATE":1,"quick_actions":6,"quick_editor":7}],3:[function(require,module,exports){ +},{"STATE":1,"quick_actions":7,"quick_editor":8}],3:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -261,9 +259,7 @@ async function actions(opts, protocol) { function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject(data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function iconject(data) { @@ -493,7 +489,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/actions/actions.js") -},{"STATE":1,"quick_editor":7}],4:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],4:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -608,9 +604,7 @@ async function console_history (opts, protocol) { } function inject (data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function oncommands (data) { @@ -835,7 +829,458 @@ function fallback_module () { } } }).call(this)}).call(this,"/src/node_modules/console_history/console_history.js") -},{"STATE":1,"quick_editor":7}],5:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],5:[function(require,module,exports){ +(function (__filename){(function (){ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +module.exports = graph_explorer + +async function graph_explorer (opts, protocol) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + const on = { + style: inject, + graph_data: on_graph_data, + icons: iconject + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
+
+
+ ` + + const style = shadow.querySelector('style') + const graph_entries = shadow.querySelector('.graph-entries') + + let init = false + let graph_data = [] + let icons = {} + let expanded_entries = new Set() + let super_nodes = new Map() + let visible_super_nodes = new Set() + + const subs = await sdb.watch(onbatch) + let send = null + let _ = null + if (protocol) { + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } + + return el + + function create_graph_entry(entry, level = 0, parent_path = '', parent_entry = null) { + const entry_el = document.createElement('div') + entry_el.className = 'graph-entry' + entry_el.style.paddingLeft = `${level * 20}px` + + const current_path = parent_path ? `${parent_path}/${entry.name}` : entry.name + const has_children = entry.children && entry.children.length > 0 + const is_expanded = expanded_entries.has(current_path) + + // Store parent relationship + if (parent_entry) { + super_nodes.set(current_path, parent_entry) + } + + const tree_symbol = get_tree_symbol(entry, level, is_expanded, has_children) + const icon = icons[entry.type] || entry.icon || '๐Ÿ“' + + entry_el.innerHTML = ` + ${tree_symbol} + ${icon} + ${entry.name} + ` + + const tree_symbol_el = entry_el.querySelector('.tree-symbol') + const icon_el = entry_el.querySelector('.entry-icon') + + // Add click event to tree symbol to show super node + if (parent_entry && level > 0) { + tree_symbol_el.onclick = () => toggle_super_node(current_path, parent_entry) + tree_symbol_el.style.cursor = 'pointer' + tree_symbol_el.title = `Show parent: ${parent_entry.name}` + } + + // Add click event to icon for expanding children + if (has_children) { + icon_el.onclick = () => toggle_entry(current_path, entry) + } + + return entry_el + } + + function get_tree_symbol(entry, level, is_expanded, has_children) { + if (level === 0) { + return has_children ? (is_expanded ? '๐Ÿช„โ”ฌ' : '๐Ÿช„โ”€') : '๐Ÿช„โ”€' + } + + if (has_children) { + return is_expanded ? 'โ”œโ”ฌ' : 'โ”œโ”€' + } else { + return 'โ”œโ”€' + } + } + + function toggle_entry(path, entry) { + if (expanded_entries.has(path)) { + expanded_entries.delete(path) + } else { + expanded_entries.add(path) + } + render_graph() + + if (protocol && _) { + _.up({ + type: 'entry_toggled', + data: { path, expanded: expanded_entries.has(path), entry } + }) + } + } + + function toggle_super_node(child_path, parent_entry) { + const super_node_key = `super_${child_path}` + + if (visible_super_nodes.has(super_node_key)) { + visible_super_nodes.delete(super_node_key) + } else { + visible_super_nodes.add(super_node_key) + } + + render_graph() + + if (protocol && _) { + _.up({ + type: 'super_node_toggled', + data: { child_path, parent_entry, visible: visible_super_nodes.has(super_node_key) } + }) + } + } + + function create_super_node_entry(parent_entry, child_path, level) { + const super_node_el = document.createElement('div') + super_node_el.className = 'graph-entry super-node' + super_node_el.style.paddingLeft = `${(level - 1) * 20}px` + + const parent_icon = icons[parent_entry.type] || parent_entry.icon || '๐Ÿ“' + + super_node_el.innerHTML = ` + โ”Œโ”€ + ${parent_icon} + ${parent_entry.name} + (parent) + ` + + return super_node_el + } + + function render_graph() { + graph_entries.innerHTML = '' + super_nodes.clear() // Clear previous parent relationships + + graph_data.forEach(entry => { + render_entry_with_super_nodes(entry) + }) + } + + function render_entry_with_super_nodes(entry, level = 0, parent_path = '', parent_entry = null) { + const current_path = parent_path ? `${parent_path}/${entry.name}` : entry.name + const super_node_key = `super_${current_path}` + + // Show super node if it's visible + if (level > 0 && visible_super_nodes.has(super_node_key) && parent_entry) { + const super_node_el = create_super_node_entry(parent_entry, current_path, level) + graph_entries.appendChild(super_node_el) + } + + // Create and append the main entry + const entry_el = create_graph_entry(entry, level, parent_path, parent_entry) + graph_entries.appendChild(entry_el) + + // Recursively render children if expanded + const has_children = entry.children && entry.children.length > 0 + const is_expanded = expanded_entries.has(current_path) + + if (is_expanded && has_children) { + entry.children.forEach(child => { + render_entry_with_super_nodes(child, level + 1, current_path, entry) + }) + } + } + + function onmessage ({ type, data }) { + if (type === 'expand_entry') { + expanded_entries.add(data.path) + render_graph() + } else if (type === 'collapse_entry') { + expanded_entries.delete(data.path) + render_graph() + } else if (type === 'show_super_node') { + visible_super_nodes.add(`super_${data.path}`) + render_graph() + } else if (type === 'hide_super_node') { + visible_super_nodes.delete(`super_${data.path}`) + render_graph() + } + } + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + if (!init && graph_data.length > 0) { + render_graph() + init = true + } + } + + function fail(data, type) { + throw new Error('invalid message', { cause: { data, type } }) + } + + function inject(data) { + style.innerHTML = data.join('\n') + } + + function on_graph_data(data) { + graph_data = JSON.parse(data[0]) + } + + function iconject(data) { + icons = { + root: data[0] || '๐ŸŒ', + folder: data[1] || '๐Ÿ“', + code: data[2] || '๐Ÿ“š', + data: data[3] || '๐Ÿ“', + tasks: data[4] || '๐Ÿ—„๏ธ' + } + } +} + +function fallback_module () { + return { + api: fallback_instance + } + + function fallback_instance () { + return { + drive: { + 'style/': { + 'theme.css': { + raw: ` + .graph-explorer-container { + background-color: #0d1117; + color: #c9d1d9; + font-family: 'Courier New', monospace; + font-size: 14px; + line-height: 1.4; + padding: 12px; + border-radius: 6px; + border: 1px solid #21262d; + min-height: 200px; + max-height: 400px; + overflow-y: auto; + } + .graph-entries { + display: flex; + flex-direction: column; + gap: 2px; + } + .graph-entry { + display: flex; + align-items: center; + gap: 4px; + padding: 2px 0; + white-space: nowrap; + user-select: none; + } + .tree-symbol { + color: #7c3aed; + font-weight: bold; + min-width: 24px; + } + .entry-icon { + cursor: pointer; + font-size: 16px; + transition: transform 0.1s ease; + min-width: 20px; + } + .entry-icon:hover { + transform: scale(1.1); + } + .entry-name { + color: #f0f6fc; + font-weight: 500; + } + .super-node { + background-color: #1c2128; + border-left: 2px solid #7c3aed; + margin: 1px 0; + border-radius: 3px; + padding: 2px 4px; + } + .super-node .tree-symbol { + color: #fbbf24; + } + .super-node-icon { + opacity: 0.8; + cursor: default !important; + } + .super-node-name { + color: #fbbf24; + font-weight: 600; + } + .super-node-label { + color: #6b7280; + font-size: 12px; + font-style: italic; + margin-left: 8px; + } + .graph-explorer-container::-webkit-scrollbar { + width: 6px; + } + .graph-explorer-container::-webkit-scrollbar-track { + background: #161b22; + border-radius: 3px; + } + .graph-explorer-container::-webkit-scrollbar-thumb { + background: #30363d; + border-radius: 3px; + } + .graph-explorer-container::-webkit-scrollbar-thumb:hover { + background: #484f58; + } + ` + } + }, + 'graph_data/': { + 'structure.json': { + raw: JSON.stringify([ + { + name: '/', + type: 'root', + icon: '๐ŸŒ', + children: [ + { + name: 'pins/', + type: 'folder', + icon: '๐Ÿ“', + children: [] + }, + { + name: 'code/', + type: 'code', + icon: '๐Ÿ“š', + children: [ + { + name: 'playproject_website', + type: 'folder', + icon: '๐Ÿ“–', + children: [ + { + name: 'index.html', + type: 'file', + icon: '๐Ÿ“„', + children: [] + }, + { + name: 'main.js', + type: 'file', + icon: '๐Ÿ“„', + children: [] + } + ] + }, + { + name: 'theme_widget', + type: 'folder', + icon: '๐Ÿ“–', + children: [ + { + name: 'widget.html', + type: 'file', + icon: '๐Ÿ“„', + children: [] + }, + { + name: 'widget.js', + type: 'file', + icon: '๐Ÿ“„', + children: [] + } + ] + } + ] + }, + { + name: 'data/', + type: 'data', + icon: '๐Ÿ“', + children: [ + { + name: 'themes/', + type: 'folder', + icon: '๐Ÿ“', + children: [ + { + name: 'fantasy.json', + type: 'file', + icon: '๐ŸŽจ', + children: [] + }, + { + name: 'night.json', + type: 'file', + icon: '๐ŸŽจ', + children: [] + } + ] + } + ] + }, + { + name: 'tasks/', + type: 'tasks', + icon: '๐Ÿ—„๏ธ', + children: [] + } + ] + } + ]) + } + }, + 'icons/': { + 'root.txt': { + raw: '๐ŸŒ' + }, + 'folder.txt': { + raw: '๐Ÿ“' + }, + 'code.txt': { + raw: '๐Ÿ“š' + }, + 'data.txt': { + raw: '๐Ÿ“' + }, + 'tasks.txt': { + raw: '๐Ÿ—„๏ธ' + } + } + } + } + } +} + +}).call(this)}).call(this,"/src/node_modules/graph_explorer.js") +},{"STATE":1}],6:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -946,9 +1391,7 @@ async function create_component_menu (opts, names, inicheck, callbacks) { function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } } function fallback_module () { @@ -1097,7 +1540,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/menu.js") -},{"STATE":1,"quick_editor":7}],6:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],7:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -1248,9 +1691,7 @@ async function quick_actions(opts, protocol) { function fail (data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject(data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function onhardcons(data) { hardcons = { @@ -1483,7 +1924,7 @@ function fallback_module() { } } }).call(this)}).call(this,"/src/node_modules/quick_actions/quick_actions.js") -},{"STATE":1,"quick_editor":7}],7:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],8:[function(require,module,exports){ module.exports = editor let count = 0 let first = true @@ -1636,7 +2077,7 @@ function init ({ style, inject, drive, text }, el) { } } } -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -1645,6 +2086,7 @@ const { sdb, get } = statedb(fallback_module) const console_history = require('console_history') const actions = require('actions') const tabbed_editor = require('tabbed_editor') +const graph_explorer = require('graph_explorer') const editor = require('quick_editor') module.exports = component @@ -1660,6 +2102,7 @@ async function component (opts, protocol) { const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
+ @@ -1668,6 +2111,7 @@ async function component (opts, protocol) { ` const style = shadow.querySelector('style') const main = shadow.querySelector('.main') + const graph_explorer_placeholder = shadow.querySelector('graph-explorer-placeholder') const actions_placeholder = shadow.querySelector('actions-placeholder') const tabbed_editor_placeholder = shadow.querySelector('tabbed-editor-placeholder') const console_placeholder = shadow.querySelector('console-history-placeholder') @@ -1677,15 +2121,20 @@ async function component (opts, protocol) { let console_history_el = null let actions_el = null let tabbed_editor_el = null + let graph_explorer_el = null const subs = await sdb.watch(onbatch) let send = null let _ = null if(protocol) { send = protocol(msg => onmessage(msg)) - _ = { up: send, actions: null, send_console_history: null, send_tabbed_editor: null } + _ = { up: send, actions: null, send_console_history: null, send_tabbed_editor: null, send_graph_explorer: null } } + graph_explorer_el = protocol ? await graph_explorer(subs[3], graph_explorer_protocol) : await graph_explorer(subs[3]) + graph_explorer_el.classList.add('graph-explorer') + graph_explorer_placeholder.replaceWith(graph_explorer_el) + actions_el = protocol ? await actions(subs[1], actions_protocol) : await actions(subs[1]) actions_el.classList.add('actions') actions_placeholder.replaceWith(actions_el) @@ -1700,11 +2149,13 @@ async function component (opts, protocol) { let console_view = false let actions_view = false let tabbed_editor_view = true + let graph_explorer_view = false if (protocol) { console_history_el.classList.add('hide') actions_el.classList.add('hide') tabbed_editor_el.classList.add('show') + graph_explorer_el.classList.add('hide') } return el @@ -1731,6 +2182,17 @@ async function component (opts, protocol) { actions_view = !actions_view } + function graph_explorer_toggle_view() { + if(graph_explorer_view) { + graph_explorer_el.classList.remove('show') + graph_explorer_el.classList.add('hide') + } else { + graph_explorer_el.classList.remove('hide') + graph_explorer_el.classList.add('show') + } + graph_explorer_view = !graph_explorer_view + } + function tabbed_editor_toggle_view(show = true) { if (show) { tabbed_editor_el.classList.remove('hide') @@ -1739,9 +2201,12 @@ async function component (opts, protocol) { actions_el.classList.add('hide') console_history_el.classList.remove('show') console_history_el.classList.add('hide') + graph_explorer_el.classList.remove('show') + graph_explorer_el.classList.add('hide') tabbed_editor_view = true actions_view = false console_view = false + graph_explorer_view = false } else { tabbed_editor_el.classList.remove('show') tabbed_editor_el.classList.add('hide') @@ -1791,8 +2256,17 @@ async function component (opts, protocol) { } } + function graph_explorer_protocol (send) { + _.send_graph_explorer = send + return on + function on ({ type, data }) { + _.up({ type, data }) + } + } + function onmessage ({ type, data }) { if(type == 'console_history_toggle') console_history_toggle_view() + else if (type == 'graph_explorer_toggle') graph_explorer_toggle_view() else if (type == 'display_actions') actions_toggle_view(data) else if (type == 'filter_actions') _.send_actions({ type, data }) else if (type == 'tab_name_clicked') { @@ -1812,6 +2286,11 @@ async function component (opts, protocol) { _.send_tabbed_editor({ type, data }) } } + else if (type == 'entry_toggled') { + if (_.send_graph_explorer) { + _.send_graph_explorer({ type, data }) + } + } } } @@ -1828,6 +2307,9 @@ function fallback_module () { 'tabbed_editor': { $: '' }, + 'graph_explorer': { + $: '' + }, 'quick_editor': 0 } } @@ -1861,6 +2343,14 @@ function fallback_module () { 'highlight': 'highlight', 'active_tab': 'active_tab' } + }, + 'graph_explorer': { + 0: '', + mapping: { + 'style': 'style', + 'graph_data': 'graph_data', + 'icons': 'icons' + } } }, drive: { @@ -1921,7 +2411,165 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/space.js") -},{"STATE":1,"actions":3,"console_history":4,"quick_editor":7,"tabbed_editor":9}],9:[function(require,module,exports){ +},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":5,"quick_editor":8,"tabbed_editor":11}],10:[function(require,module,exports){ +(function (__filename){(function (){ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +const actions = require('actions') +const editor = require('quick_editor') + + +module.exports = steps_wizard + +async function steps_wizard (opts) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + + const on = { + style: inject, + variables: onvariables, + } + + let variables = [] + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
+
+
+
+ + ` + + const style = shadow.querySelector('style') + const main = shadow.querySelector('.main') + const actions_slot = shadow.querySelector('.actions-slot') + const steps_entries = shadow.querySelector('.steps-slot') + + + main.append(editor(style, inject = inject)) + + const subs = await sdb.watch(onbatch) + + let actions_el = null + + actions_el = await actions(subs[0]) + actions_slot.replaceWith(actions_el) + + return el + + function render_steps(steps) { + steps_entries.innerHTML = ''; + + steps.forEach((step, index) => { + const btn = document.createElement('button'); + btn.className = 'step-button'; + btn.textContent = step.name + (step.type === 'optional' ? ' *' : ''); + btn.setAttribute('data-step', index + 1); + + const accessible = can_access(index, steps); + + let status = 'default'; + if (!accessible) status = 'disabled'; + else if (step.is_completed) status = 'completed'; + else if (step.status === 'error') status = 'error'; + else if (step.type === 'optional') status = 'optional'; + + btn.classList.add(`step-${status}`); + btn.disabled = (status === 'disabled'); + + btn.onclick = () => { + if (!btn.disabled) { + step.is_completed = true + step.status = 'completed'; + console.log('Clicked:', step); + render_steps(steps); + } + }; + + steps_entries.appendChild(btn); + }); + + } + + function can_access(index, steps) { + for (let i = 0; i < index; i++) { + if (!steps[i].is_completed && steps[i].type !== 'optional') { + return false; + } + } + + return true; + } + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } + function inject (data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onvariables (data) { + const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] + variables = vars['change_path'] + render_steps(variables); + } + +} + +function fallback_module () { + return { + api: fallback_instance, + _: { + 'actions': { + $: '' + }, + 'quick_editor': 0 + } + } + + function fallback_instance () { + return { + _: { + 'actions': { + 0: '', + mapping: { + 'style': 'style', + 'actions': 'actions', + 'icons': 'icons', + 'hardcons': 'hardcons' + } + } + }, + drive: { + 'style/': { + 'stepswizard.css': { + '$ref': 'stepswizard.css' + } + }, + 'variables/': { + 'steps_wizard.json': { + '$ref': 'steps_wizard.json' + } + }, + } + } + } +} + +}).call(this)}).call(this,"/src/node_modules/steps_wizard/steps_wizard.js") +},{"STATE":1,"actions":3,"quick_editor":8}],11:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2101,9 +2749,7 @@ async function tabbed_editor(opts, protocol) { } function inject(data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function onfiles(data) { @@ -2322,7 +2968,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/tabbed_editor/tabbed_editor.js") -},{"STATE":1,"quick_editor":7}],10:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],12:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2469,9 +3115,7 @@ async function component (opts, protocol) { } function fail (data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function onvariables (data) { @@ -2541,7 +3185,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/tabs/tabs.js") -},{"STATE":1,"quick_editor":7}],11:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],13:[function(require,module,exports){ (function (__filename){(function (){ const state = require('STATE') const state_db = state(__filename) @@ -2637,9 +3281,7 @@ async function tabsbar (opts, protocol) { function fail (data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function inject_icons (data) { @@ -2729,7 +3371,7 @@ function fallback_module () { } } }).call(this)}).call(this,"/src/node_modules/tabsbar/tabsbar.js") -},{"STATE":1,"quick_editor":7,"tabs":10,"task_manager":12}],12:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8,"tabs":12,"task_manager":14}],14:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2776,9 +3418,7 @@ async function task_manager (opts, callback = () => console.log('task manager cl } function fail (data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } function update_count (data) { @@ -2829,7 +3469,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/task_manager.js") -},{"STATE":1,"quick_editor":7}],13:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8}],15:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2892,9 +3532,7 @@ async function taskbar(opts, protocol) { function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject(data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } // --------- @@ -2992,7 +3630,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/taskbar/taskbar.js") -},{"STATE":1,"action_bar":2,"quick_editor":7,"tabsbar":11}],14:[function(require,module,exports){ +},{"STATE":1,"action_bar":2,"quick_editor":8,"tabsbar":13}],16:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3131,7 +3769,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/theme_widget/theme_widget.js") -},{"STATE":1,"quick_editor":7,"space":8,"taskbar":13}],15:[function(require,module,exports){ +},{"STATE":1,"quick_editor":8,"space":9,"taskbar":15}],17:[function(require,module,exports){ const hash = 'dd5a8a33c1ca1228ed3f4284b3067f36a0d2873e' const prefix = 'https://raw.githubusercontent.com/alyhxn/playproject/' + hash + '/' const init_url = prefix + 'doc/state/example/init.js' @@ -3145,7 +3783,7 @@ fetch(init_url, { cache: 'no-store' }).then(res => res.text()).then(async source await init(args, prefix) require('./page') }) -},{"./page":16}],16:[function(require,module,exports){ +},{"./page":18}],18:[function(require,module,exports){ (function (__filename){(function (){ localStorage.clear() const STATE = require('../src/node_modules/STATE') @@ -3167,7 +3805,9 @@ const actions = require('../src/node_modules/actions') const tabbed_editor = require('../src/node_modules/tabbed_editor') const task_manager = require('../src/node_modules/task_manager') const quick_actions = require('../src/node_modules/quick_actions') +const graph_explorer = require('../src/node_modules/graph_explorer') const editor = require('../src/node_modules/quick_editor') +const steps_wizard = require('../src/node_modules/steps_wizard') const imports = { theme_widget, @@ -3180,7 +3820,9 @@ const imports = { actions, tabbed_editor, task_manager, - quick_actions + quick_actions, + graph_explorer, + steps_wizard, } config().then(() => boot({ sid: '' })) @@ -3389,9 +4031,7 @@ async function create_component (entries_obj) { } function fail (data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject(data) { - style.replaceChildren((() => { - return document.createElement('style').textContent = data[0] - })()) + style.innerHTML = data.join('\n') } } function fallback_module () { @@ -3407,7 +4047,9 @@ function fallback_module () { '../src/node_modules/actions', '../src/node_modules/tabbed_editor', '../src/node_modules/task_manager', - '../src/node_modules/quick_actions' + '../src/node_modules/quick_actions', + '../src/node_modules/graph_explorer', + '../src/node_modules/steps_wizard' ] const subs = {} names.forEach(subgen) @@ -3421,6 +4063,14 @@ function fallback_module () { 'style': 'style' } } + subs['../src/node_modules/steps_wizard'] = { + $: '', + 0: '', + mapping: { + 'variables': 'variables', + 'style': 'style' + } + } subs['../src/node_modules/tabsbar'] = { $: '', 0: '', @@ -3485,6 +4135,15 @@ function fallback_module () { 'hardcons': 'hardcons' } } + subs['../src/node_modules/graph_explorer'] = { + $: '', + 0: '', + mapping: { + 'style': 'style', + 'graph_data': 'graph_data', + 'icons': 'icons' + } + } subs[menuname] = { $: '', 0: '', @@ -3594,4 +4253,4 @@ function fallback_module () { } }).call(this)}).call(this,"/web/page.js") -},{"../src/node_modules/STATE":1,"../src/node_modules/action_bar":2,"../src/node_modules/actions":3,"../src/node_modules/console_history":4,"../src/node_modules/menu":5,"../src/node_modules/quick_actions":6,"../src/node_modules/quick_editor":7,"../src/node_modules/space":8,"../src/node_modules/tabbed_editor":9,"../src/node_modules/tabs":10,"../src/node_modules/tabsbar":11,"../src/node_modules/task_manager":12,"../src/node_modules/taskbar":13,"../src/node_modules/theme_widget":14}]},{},[15]); +},{"../src/node_modules/STATE":1,"../src/node_modules/action_bar":2,"../src/node_modules/actions":3,"../src/node_modules/console_history":4,"../src/node_modules/graph_explorer":5,"../src/node_modules/menu":6,"../src/node_modules/quick_actions":7,"../src/node_modules/quick_editor":8,"../src/node_modules/space":9,"../src/node_modules/steps_wizard":10,"../src/node_modules/tabbed_editor":11,"../src/node_modules/tabs":12,"../src/node_modules/tabsbar":13,"../src/node_modules/task_manager":14,"../src/node_modules/taskbar":15,"../src/node_modules/theme_widget":16}]},{},[17]); diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 53a800a..6d2f0e7 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -11,15 +11,20 @@ module.exports = steps_wizard async function steps_wizard (opts) { const { id, sdb } = await get(opts.sid) const {drive} = sdb + const on = { - style: inject + style: inject, + variables: onvariables, } + let variables = [] + const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
+
@@ -28,6 +33,8 @@ async function steps_wizard (opts) { const style = shadow.querySelector('style') const main = shadow.querySelector('.main') const actions_slot = shadow.querySelector('.actions-slot') + const steps_entries = shadow.querySelector('.steps-slot') + main.append(editor(style, inject = inject)) @@ -40,6 +47,50 @@ async function steps_wizard (opts) { return el + function render_steps(steps) { + steps_entries.innerHTML = ''; + + steps.forEach((step, index) => { + const btn = document.createElement('button'); + btn.className = 'step-button'; + btn.textContent = step.name + (step.type === 'optional' ? ' *' : ''); + btn.setAttribute('data-step', index + 1); + + const accessible = can_access(index, steps); + + let status = 'default'; + if (!accessible) status = 'disabled'; + else if (step.is_completed) status = 'completed'; + else if (step.status === 'error') status = 'error'; + else if (step.type === 'optional') status = 'optional'; + + btn.classList.add(`step-${status}`); + btn.disabled = (status === 'disabled'); + + btn.onclick = () => { + if (!btn.disabled) { + step.is_completed = true + step.status = 'completed'; + console.log('Clicked:', step); + render_steps(steps); + } + }; + + steps_entries.appendChild(btn); + }); + + } + + function can_access(index, steps) { + for (let i = 0; i < index; i++) { + if (!steps[i].is_completed && steps[i].type !== 'optional') { + return false; + } + } + + return true; + } + async function onbatch(batch) { for (const { type, paths } of batch){ const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) @@ -53,6 +104,13 @@ async function steps_wizard (opts) { return document.createElement('style').textContent = data[0] })()) } + + function onvariables (data) { + const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] + variables = vars['change_path'] + render_steps(variables); + } + } function fallback_module () { @@ -82,20 +140,14 @@ function fallback_module () { drive: { 'style/': { 'stepswizard.css': { - raw: ` - .steps-wizard { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - background: #131315; - } - .space{ - height: inherit; - } - ` + '$ref': 'stepswizard.css' } - } + }, + 'variables/': { + 'steps_wizard.json': { + '$ref': 'steps_wizard.json' + } + }, } } } diff --git a/src/node_modules/steps_wizard/steps_wizard.json b/src/node_modules/steps_wizard/steps_wizard.json new file mode 100644 index 0000000..c543551 --- /dev/null +++ b/src/node_modules/steps_wizard/steps_wizard.json @@ -0,0 +1,5 @@ +{"change_path": [ + {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "test", "status": "default"}, + {"name": "step2", "type": "optional", "is_completed": false, "component": "test1", "status": "default" }, + {"name": "step2", "type": "mandatory", "is_completed": false, "component": "test1", "status": "default" } +]} diff --git a/src/node_modules/steps_wizard/stepswizard.css b/src/node_modules/steps_wizard/stepswizard.css new file mode 100644 index 0000000..41a2396 --- /dev/null +++ b/src/node_modules/steps_wizard/stepswizard.css @@ -0,0 +1,106 @@ +.steps-wizard { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + background: #131315; +} +.space{ + height: inherit; +} +.steps-slot { + display: flex; + gap: 8px; + padding: 5px; +} +.step-button { + position: relative; + display: flex; + align-items: center; + cursor: pointer; + font-size: 16px; + padding: 10px 16px 10px 44px; + margin: 10px 0; + border-radius: 12px; + font-weight: 500; + transition: background-color 0.3s; + width: fit-content; + border: 2px solid; +} + +.step-button:before { + content: attr(data-step); + position: absolute; + left: 12px; + width: 20px; + height: 20px; + border: 1px solid white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 12px; +} + +/* Default (active step) */ +.step-default { + background-color: #224B24; + border-color: #299910; + color: white; +} +.step-default:before { + background-color: #224B24; + color: white; + border: 1px solid white; +} + +/* Optional (yellow) */ +.step-optional { + background-color: #4b3f22; + border-color: #d0a510; + color: #f4c842; +} +.step-optional:before { + background-color: #4b3f22; + border-color: #d0a510; + color: #f4c842; +} + +/* Error (red) */ +.step-error { + background-color: #4b1e1e; + border-color: #e53935; + color:rgb(248, 68, 65); +} +.step-error:before { + background-color: #4b1e1e; + border-color: #e53935; + color: rgb(248, 68, 65); +} + +/* Completed (green with checkmark) */ +.step-completed { + background-color: #224B24; + border-color: #299910; + color: white; +} +.step-completed:before { + content: "โœ”"; + background-color: #224B24; + border: 1px solid white; + color: white; +} + +/* Disabled (gray) */ +.step-disabled { + background-color: #444; + border-color: #444; + color: #ccc; + cursor: not-allowed; +} +.step-disabled:before { + background-color: #444; + border-color: #ccc; + color: #ccc; +} \ No newline at end of file diff --git a/web/page.js b/web/page.js index aec46fd..be34e80 100644 --- a/web/page.js +++ b/web/page.js @@ -276,6 +276,14 @@ function fallback_module () { 'style': 'style' } } + subs['../src/node_modules/steps_wizard'] = { + $: '', + 0: '', + mapping: { + 'variables': 'variables', + 'style': 'style' + } + } subs['../src/node_modules/tabsbar'] = { $: '', 0: '', From 6748c889ed9f5096ef52299727f024d88948a878 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 21 Jun 2025 21:46:18 +0500 Subject: [PATCH 02/21] add guide --- src/node_modules/steps_wizard/guide.md | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/node_modules/steps_wizard/guide.md diff --git a/src/node_modules/steps_wizard/guide.md b/src/node_modules/steps_wizard/guide.md new file mode 100644 index 0000000..4623889 --- /dev/null +++ b/src/node_modules/steps_wizard/guide.md @@ -0,0 +1,89 @@ +# Steps Wizard Developer Guide + +This guide is intended for developers working with the steps wizard component to understand its structure, usage, and available statuses. + +--- + +## Overview + +The steps wizard is a UI component that shows progress across multiple steps of a process. Each step has a status (e.g., pending, completed, error), and may include additional information such as optional flags or errors. + +--- + +## Status Types + +Each step can have one of the following statuses: + +### 1. `pending(default status)` +- Default status. +- Appears clickable if itโ€™s the first step or the previous one is `completed` or `optional`. +- Greyed out if it's not reachable yet. + +### 2. `optional` +- Styled with **yellow** background and border. +- Allows skipping the step and still moving forward to the next. +- The step number is highlighted in yellow. +- Used when the step is not required to continue the process. + +### 3. `error` +- Styled with **red** background and border. +- Indicates invalid or incomplete user input. +- Clicking it should bring focus to the error area and optionally display a tooltip/message. + +### 4. `completed` +- Styled with **green** background and border. +- The step number is replaced with a โœ”๏ธ tick mark. +- User can click to revisit or edit the completed step. + +--- + +## Step Accessibility Rules + +1. **First step** is always active/clickable unless disabled explicitly. +2. A step becomes **clickable** if: + - The previous step is `completed` or `optional`. +3. A step is **disabled** (unclickable) if: + - It is not the current or next possible step. + - It hasn't yet met conditions to be accessed. + - It appears grey with reduced opacity. + +--- + +## Interactivity + +Clicking on a step will: +- Change its status to `completed` (with green tick). +- Move to the next step (if available). +- Allow backward navigation to completed steps. + +--- + +## ๐Ÿงช Example Status Flow + +| Step | Status | Notes | +|------|-------------|---------------------------------------------------| +| 1 | `completed` | Shows tick, clickable to revisit | +| 2 | `optional` | Clickable, yellow style, can skip | +| 3 | `pending` | Clickable if step 2 is `completed` or `optional` | +| 4 | `error` | Red border, must fix before proceeding | + +--- + +## Style Notes + +| Status | Color | Icon/Text | +|------------|-----------|-----------------------| +| pending | Grey | Number inside circle | +| optional | Yellow | Number + `*` suffix | +| error | Red | Number + error style | +| completed | Green | โœ”๏ธ tick instead of number | + +--- + +## Example Step HTML + +```html + +``` \ No newline at end of file From 37be424525931ca0250bbf892a2847349efc029e Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sun, 22 Jun 2025 20:52:11 +0500 Subject: [PATCH 03/21] change to minimal code --- bundle.js | 36 ++----------------- src/node_modules/steps_wizard/steps_wizard.js | 34 +----------------- .../steps_wizard/steps_wizard.json | 4 +-- 3 files changed, 5 insertions(+), 69 deletions(-) diff --git a/bundle.js b/bundle.js index 6b7e6b0..8f1830d 100644 --- a/bundle.js +++ b/bundle.js @@ -2389,10 +2389,6 @@ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const actions = require('actions') -const editor = require('quick_editor') - - module.exports = steps_wizard async function steps_wizard (opts) { @@ -2410,7 +2406,6 @@ async function steps_wizard (opts) { const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
-
+ ` - .quick-editor .dots-button { - border: none; - font-size: 24px; - cursor: pointer; - line-height: 1; - background-color: white; - letter-spacing: 1px; - padding: 3px 5px; - border-radius: 20%; - box-shadow: 0 2px 4px rgba(0,0,0,0.3); - } + const style = shadow.querySelector('style') + const menu_btn = shadow.querySelector('.dots-button') + const menu = shadow.querySelector('.quick-menu') + const textarea = shadow.querySelector('textarea') + const apply_btn = shadow.querySelector('.apply-button') + const top_btns = shadow.querySelector('.top-btns') + const top_tabs = shadow.querySelector('.top-tabs') + // ---------------------------------------- + // EVENTS + // ---------------------------------------- + await sdb.watch(onbatch) + menu_btn.onclick = menu_click + apply_btn.onclick = apply + + io.on(port => { + const { by, to } = port + port.onmessage = event => { + const txt = event.data + const key = `[${by} -> ${to}]` + data = txt + } + }) + const port = await io.at(net.page.id) + + return el - .quick-editor .quick-menu { - position: absolute; - top: 100%; - left: 0; - background: white; - padding: 8px; - box-shadow: 0 2px 8px rgba(0,0,0,0.15); - white-space: nowrap; - z-index: 10; + // ---------------------------------------- + // FUNCTIONS + // ---------------------------------------- + function make_btn (name, classes) { + const btn = document.createElement('button') + btn.textContent = name + btn.classList.add(...classes.split(' ')) + btn.setAttribute('tab', name) + return btn + } + function make_tab (id, classes) { + const tab = document.createElement('div') + tab.classList.add(...classes.split(' ')) + tab.id = id.replaceAll('.', '') + tab.innerHTML = ` +
+
+
+
+ ` + return tab + } + function make_textarea (id, classes, value) { + const textarea = document.createElement('textarea') + textarea.id = id.replaceAll('.', '') + textarea.classList.add(...classes.split(' ')) + textarea.value = value + textarea.placeholder = 'Type here...' + return textarea + } + async function menu_click () { + menu.classList.toggle('hidden') + if(init) + return + init = true + Object.entries(data).forEach(([dataset, files], i) => { + let first = '' + if(!i){ + first = ' active' + current_data.dataset = dataset } + const no_slash = dataset.split('/')[0] + const btn = make_btn(no_slash, `tab-button${first}`) + const tab = make_tab(no_slash, `tab-content${first}`) - .quick-editor .quick-menu textarea { - width: 300px; - height: 400px; - resize: vertical; - } + btn.onclick = () => tab_btn_click(btn, top_btns, top_tabs, '.tab-content', 'dataset', dataset) + + top_btns.append(btn) + top_tabs.append(tab) + + const sub_btns = tab.querySelector('.sub-btns') + const subtab = tab.querySelector('.subtab-content') + Object.entries(files).forEach(([file, raw], j) => { + let first = '' + if(!j){ + first = ' active' + current_data.file = file + } + const sub_btn = make_btn(file, `sub-btn${first}`) + const textarea = make_textarea(file, `subtab-textarea${first}`, raw) - .quick-editor .hidden { - display: none; - } - .quick-editor .apply-button { - display: block; - margin-top: 10px; - padding: 5px 10px; - background-color: #4CAF50; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - } - - ` - const btn = el.querySelector('.dots-button') - const menu = el.querySelector('.quick-menu') - const textarea = el.querySelector('textarea') - const applyBtn = el.querySelector('.apply-button') + sub_btn.onclick = () => tab_btn_click(sub_btn, sub_btns, subtab, '.subtab-textarea', 'file', file) - btn.addEventListener('click', (e) => { - menu.classList.toggle('hidden') - textarea.value = text || style.innerHTML - // Auto reposition to avoid overflow - const rect = menu.getBoundingClientRect() - const overflowRight = rect.right > window.innerWidth - const overflowLeft = rect.left < 0 - - if (overflowRight) { - menu.style.left = 'auto' - menu.style.right = '0' - } else if (overflowLeft) { - menu.style.left = '0' - menu.style.right = 'auto' - } else { - menu.style.left = '0' - menu.style.right = 'auto' - } - }) + sub_btns.append(sub_btn) + subtab.append(textarea) + }) + }) + } + function tab_btn_click (btn, btns, tabs, tab_class, key, name) { + btns.querySelector('.active').classList.remove('active') + tabs.querySelector(tab_class+'.active').classList.remove('active') - applyBtn.addEventListener('click', apply) + btn.classList.add('active') + tabs.querySelector('#'+btn.getAttribute('tab').replaceAll('.', '')).classList.add('active') + current_data[key] = name + + } - textarea.addEventListener('keydown', function(e) { - if (e.ctrlKey && e.key === 'Enter') { - apply() + function apply() { + port.postMessage({ type: 'put', args: [ + current_data.dataset + current_data.file, + shadow.querySelector('.tab-content.active textarea.active').value + ]}) + } + + function inject (data) { + style.textContent = data.join('\n') + } + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) } - }) + } - return el + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } - function apply() { - if (style && textarea) { - inject([textarea.value]) +} + + +function fallback_module(){ + return { + api: fallback_instance + } + function fallback_instance(){ + return { + drive: { + 'style/': { + 'quick_editor.css': { + raw: ` + .dots-button { + border: none; + font-size: 24px; + cursor: pointer; + line-height: 1; + background-color: white; + letter-spacing: 1px; + padding: 3px 5px; + border-radius: 20%; + box-shadow: 0 2px 4px rgba(0,0,0,0.3); + } + + .quick-menu { + position: absolute; + top: 100%; + right: 0; + background: white; + padding: 8px; + box-shadow: 0 2px 8px rgba(0,0,0,0.15); + white-space: nowrap; + z-index: 10; + width: 400px; + } + + .hidden { + display: none; + } + + .top-btns { + display: flex; + margin-bottom: 8px; + } + + .tab-button { + flex: 1; + padding: 6px 10px; + background: #eee; + border: none; + cursor: pointer; + border-bottom: 2px solid transparent; + } + .tab-button.active { + background: white; + border-bottom: 2px solid #4CAF50; + } + .tab-content { + display: none; + } + .tab-content.active { + display: block; + } + + .sub-btns { + float: right; + display: flex; + flex-direction: column; + gap: 4px; + margin-left: 5px; + } + + .sub-btn { + padding: 4px 8px; + background: #f1f1f1; + border: none; + cursor: pointer; + text-align: right; + } + .sub-btn.active { + background: #d0f0d0; + } + + .subtab-content { + overflow: hidden; + } + + .subtab-textarea { + width: 300px; + height: 400px; + display: none; + resize: vertical; + } + .subtab-textarea.active { + display: block; + } + + .apply-button { + display: block; + margin-top: 10px; + padding: 5px 10px; + background-color: #4CAF50; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + } + + ` + } + } + } } } } -},{}],9:[function(require,module,exports){ +}).call(this)}).call(this,"/src/node_modules/quick_editor.js") +},{"STATE":1}],9:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -1951,7 +2057,6 @@ const console_history = require('console_history') const actions = require('actions') const tabbed_editor = require('tabbed_editor') const graph_explorer = require('graph_explorer') -const editor = require('quick_editor') module.exports = component @@ -1980,7 +2085,6 @@ async function component (opts, protocol) { const tabbed_editor_placeholder = shadow.querySelector('tabbed-editor-placeholder') const console_placeholder = shadow.querySelector('console-history-placeholder') - main.append(editor(style, inject)) let console_history_el = null let actions_el = null @@ -2173,8 +2277,7 @@ function fallback_module () { }, 'graph_explorer': { $: '' - }, - 'quick_editor': 0 + } } } @@ -2275,7 +2378,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/space.js") -},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":5,"quick_editor":8,"tabbed_editor":11}],10:[function(require,module,exports){ +},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":5,"tabbed_editor":11}],10:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2287,6 +2390,8 @@ async function steps_wizard (opts) { const { id, sdb } = await get(opts.sid) const {drive} = sdb + let init = false; + const on = { style: inject, variables: onvariables, @@ -2312,6 +2417,8 @@ async function steps_wizard (opts) { return el function render_steps(steps) { + if (!steps) + return; steps_entries.innerHTML = ''; steps.forEach((step, index) => { @@ -2337,6 +2444,7 @@ async function steps_wizard (opts) { step.status = 'completed'; console.log('Clicked:', step); render_steps(steps); + console.log("data is pushed through put", drive.put('variables/steps_wizard.json', steps)) } }; @@ -2360,7 +2468,7 @@ async function steps_wizard (opts) { const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) const func = on[type] || fail func(data, type) - } + } } function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { @@ -2371,8 +2479,11 @@ async function steps_wizard (opts) { function onvariables (data) { const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] - variables = vars['change_path'] - render_steps(variables); + variables = vars['change_path'] + if (!init) { + render_steps(variables); + init = true + } } } @@ -2406,7 +2517,6 @@ function fallback_module () { const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const editor = require('quick_editor') module.exports = tabbed_editor async function tabbed_editor(opts, protocol) { @@ -2434,7 +2544,6 @@ async function tabbed_editor(opts, protocol) { const main = shadow.querySelector('.main') const editor_content = shadow.querySelector('.editor-content') - main.append(editor(style, inject)) let init = false let files = {} @@ -2608,10 +2717,7 @@ async function tabbed_editor(opts, protocol) { function fallback_module() { return { - api: fallback_instance, - _: { - 'quick_editor': 0 - } + api: fallback_instance } function fallback_instance() { @@ -2800,12 +2906,11 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/tabbed_editor/tabbed_editor.js") -},{"STATE":1,"quick_editor":8}],12:[function(require,module,exports){ +},{"STATE":1}],12:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const editor = require('quick_editor') module.exports = component async function component (opts, protocol) { @@ -2827,7 +2932,6 @@ async function component (opts, protocol) { const style = shadow.querySelector('style') const main = shadow.querySelector('.main') - main.append(editor(style, inject)) let init = false let variables = [] @@ -2975,9 +3079,6 @@ async function component (opts, protocol) { function fallback_module () { return { api: fallback_instance, - _:{ - 'quick_editor': 0 - } } function fallback_instance () { return { @@ -3017,7 +3118,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/tabs/tabs.js") -},{"STATE":1,"quick_editor":8}],13:[function(require,module,exports){ +},{"STATE":1}],13:[function(require,module,exports){ (function (__filename){(function (){ const state = require('STATE') const state_db = state(__filename) @@ -3025,7 +3126,6 @@ const { sdb, get } = state_db(fallback_module) const tabs_component = require('tabs') const task_manager = require('task_manager') -const editor = require('quick_editor') module.exports = tabsbar @@ -3062,7 +3162,6 @@ async function tabsbar (opts, protocol) { const hat_btn = shadow.querySelector('.hat-btn') const bar_btn = shadow.querySelector('.bar-btn') - main.append(editor(style, inject)) const subs = await sdb.watch(onbatch) if (dricons[0]) { const parser = new DOMParser() @@ -3131,7 +3230,6 @@ function fallback_module () { task_manager: { $: '' }, - 'quick_editor': 0 } } @@ -3203,12 +3301,11 @@ function fallback_module () { } } }).call(this)}).call(this,"/src/node_modules/tabsbar/tabsbar.js") -},{"STATE":1,"quick_editor":8,"tabs":12,"task_manager":14}],14:[function(require,module,exports){ +},{"STATE":1,"tabs":12,"task_manager":14}],14:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const editor = require('quick_editor') module.exports = task_manager async function task_manager (opts, callback = () => console.log('task manager clicked')) { @@ -3233,7 +3330,6 @@ async function task_manager (opts, callback = () => console.log('task manager cl const main = shadow.querySelector('.main') const btn = shadow.querySelector('.task-count-btn') - main.append(editor(style, inject)) btn.onclick = callback @@ -3262,9 +3358,6 @@ async function task_manager (opts, callback = () => console.log('task manager cl function fallback_module () { return { api: fallback_instance, - _: { - 'quick_editor': 0 - } } function fallback_instance () { @@ -3301,12 +3394,11 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/task_manager.js") -},{"STATE":1,"quick_editor":8}],15:[function(require,module,exports){ +},{"STATE":1}],15:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const editor = require('quick_editor') const action_bar = require('action_bar') const tabsbar = require('tabsbar') @@ -3334,7 +3426,6 @@ async function taskbar(opts, protocol) { const action_bar_slot = shadow.querySelector('.action-bar-slot') const tabsbar_slot = shadow.querySelector('.tabsbar-slot') - main.append(editor(style, inject)) const subs = await sdb.watch(onbatch) let send = null @@ -3410,7 +3501,6 @@ function fallback_module() { 'tabsbar': { $: '' }, - 'quick_editor': 0 } } @@ -3462,7 +3552,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/taskbar/taskbar.js") -},{"STATE":1,"action_bar":2,"quick_editor":8,"tabsbar":13}],16:[function(require,module,exports){ +},{"STATE":1,"action_bar":2,"tabsbar":13}],16:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3470,7 +3560,6 @@ const { sdb, get } = statedb(fallback_module) const space = require('space') const taskbar = require('taskbar') -const editor = require('quick_editor') module.exports = theme_widget @@ -3497,7 +3586,6 @@ async function theme_widget (opts) { const space_slot = shadow.querySelector('.space-slot') const taskbar_slot = shadow.querySelector('.taskbar-slot') - main.append(editor(style, inject = inject)) const subs = await sdb.watch(onbatch) @@ -3558,7 +3646,6 @@ function fallback_module () { 'taskbar': { $: '' }, - 'quick_editor': 0 } } @@ -3601,10 +3688,9 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/theme_widget/theme_widget.js") -},{"STATE":1,"quick_editor":8,"space":9,"taskbar":15}],17:[function(require,module,exports){ -const hash = 'dd5a8a33c1ca1228ed3f4284b3067f36a0d2873e' -const prefix = 'https://raw.githubusercontent.com/alyhxn/playproject/' + hash + '/' -const init_url = prefix + 'doc/state/example/init.js' +},{"STATE":1,"space":9,"taskbar":15}],17:[function(require,module,exports){ +const prefix = 'https://raw.githubusercontent.com/alyhxn/playproject/main/' +const init_url = location.hash === '#dev' ? 'web/init.js' : prefix + 'src/node_modules/init.js' const args = arguments const has_save = location.hash.includes('#save') @@ -3620,14 +3706,15 @@ fetch(init_url, fetch_opts).then(res => res.text()).then(async source => { f(module, require) const init = module.exports await init(args, prefix) - require('./page') + require('./page') // or whatever is otherwise the main entry of our project }) + },{"./page":18}],18:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('../src/node_modules/STATE') const statedb = STATE(__filename) -const { sdb } = statedb(fallback_module) -const {drive} = sdb +const { sdb, io } = statedb(fallback_module) +const { drive, admin } = sdb /****************************************************************************** PAGE ******************************************************************************/ @@ -3690,7 +3777,8 @@ async function boot (opts) { // ID + JSON STATE // ---------------------------------------- const on = { - style: inject + style: inject, + ...sdb.admin.status.dataset.drive } // const status = {} // ---------------------------------------- @@ -3699,10 +3787,6 @@ async function boot (opts) { const el = document.body const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = ` -
@@ -3711,9 +3795,7 @@ async function boot (opts) { ` el.style.margin = 0 el.style.backgroundColor = '#d8dee9' - const editor_btn = shadow.querySelector('input') - const toggle = editor() - editor_btn.onclick = toggle + // ---------------------------------------- // ELEMENTS @@ -3725,6 +3807,7 @@ async function boot (opts) { const entries = Object.entries(imports) const wrappers = [] + const pairs = {} const names = entries.map(([name]) => name) let current_selected_wrapper = null @@ -3751,12 +3834,26 @@ async function boot (opts) { on_label_click: handle_label_click, on_select_all_toggle: handle_select_all_toggle } + io.on(port => { + const { by, to } = port + port.onmessage = event => { + const txt = event.data + const key = `[${by} -> ${to}]` + on[txt.type] && on[txt.type](...txt.args, pairs[to]) + + } + }) + + + const editor_subs = await sdb.get_sub("page>../src/node_modules/quick_editor") const subs = (await sdb.watch(onbatch)).filter((_, index) => index % 2 === 0) - console.log('subs', subs) + console.log('Page subs', subs) const nav_menu_element = await navbar(subs[names.length], names, initial_checked_indices, menu_callbacks) navbar_slot.replaceWith(nav_menu_element) create_component(entries) window.onload = scroll_to_initial_selected + + return el async function create_component (entries_obj) { let index = 0 @@ -3773,7 +3870,30 @@ async function create_component (entries_obj) { const component_content = await factory(subs[index]) console.log('component_content', index) component_content.className = 'component-content' - inner.append(component_content) + + const node_id = admin.status.s2i[subs[index].sid] + const editor_id = admin.status.a2i[admin.status.s2i[editor_subs[index].sid]] + inner.append(component_content, await editor(editor_subs[index])) + + + const result = {} + const drive = admin.status.dataset.drive + + pairs[editor_id] = node_id + + const datasets = drive.list('', node_id) + for(dataset of datasets) { + result[dataset] = {} + const files = drive.list(dataset, node_id) + for(file of files){ + result[dataset][file] = (await drive.get(dataset+file, node_id)).raw + } + } + + + const port = await io.at(editor_id) + port.postMessage(result) + components_wrapper.appendChild(outer) wrappers[index] = { outer, inner, name, checkbox_state: is_initially_checked } index++ @@ -3990,7 +4110,16 @@ function fallback_module () { 'style': 'style', } } - subs['../src/node_modules/quick_editor'] = 0 + subs['../src/node_modules/quick_editor'] = { + $: '', + mapping: { + 'style': 'style' + } + } + for(i = 0; i < Object.keys(subs).length - 2; i++){ + subs['../src/node_modules/quick_editor'][i] = quick_editor$ + } + return { _: subs, drive: { @@ -4075,11 +4204,42 @@ function fallback_module () { input:checked + .slider::before { transform: translateX(24px); } - ` + .component-wrapper { + position: relative; + overflow: visible; + } + .component-wrapper:hover::before { + content: ''; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + border: 4px solid skyblue; + pointer-events: none; + z-index: 4; + } + .component-wrapper:hover .quick-editor { + display: block; + } + .quick-editor { + display: none; + position: absolute; + top: -5px; + right: -10px; + z-index: 5; + }` } } } } + function quick_editor$ (args, tools, [quick_editor]){ + const state = quick_editor() + state.net = { + page: {} + } + return state + } function subgen (name) { subs[name] = { $: '', From 980e9eb569c0c4b8ac3e9313235612323d4ab00b Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Tue, 24 Jun 2025 23:24:06 +0500 Subject: [PATCH 06/21] save changes --- src/node_modules/steps_wizard/steps_wizard.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 5b6dbcf..4a2828a 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -7,9 +7,7 @@ module.exports = steps_wizard async function steps_wizard (opts) { const { id, sdb } = await get(opts.sid) const {drive} = sdb - - let init = false; - + const on = { style: inject, variables: onvariables, @@ -61,8 +59,7 @@ async function steps_wizard (opts) { step.is_completed = true step.status = 'completed'; console.log('Clicked:', step); - render_steps(steps); - console.log("data is pushed through put", drive.put('variables/steps_wizard.json', steps)) + drive.put('variables/steps_wizard.json', {'change_path': steps}) } }; @@ -86,7 +83,7 @@ async function steps_wizard (opts) { const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) const func = on[type] || fail func(data, type) - } + } } function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { @@ -98,10 +95,7 @@ async function steps_wizard (opts) { function onvariables (data) { const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] variables = vars['change_path'] - if (!init) { - render_steps(variables); - init = true - } + render_steps(variables); } } From 6f57baf312587b6be50f8a2c4dc6330cdcd7dc78 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Tue, 24 Jun 2025 23:26:26 +0500 Subject: [PATCH 07/21] update bundle --- bundle.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/bundle.js b/bundle.js index 3fa7693..1fa55e7 100644 --- a/bundle.js +++ b/bundle.js @@ -2389,9 +2389,7 @@ module.exports = steps_wizard async function steps_wizard (opts) { const { id, sdb } = await get(opts.sid) const {drive} = sdb - - let init = false; - + const on = { style: inject, variables: onvariables, @@ -2443,8 +2441,7 @@ async function steps_wizard (opts) { step.is_completed = true step.status = 'completed'; console.log('Clicked:', step); - render_steps(steps); - console.log("data is pushed through put", drive.put('variables/steps_wizard.json', steps)) + drive.put('variables/steps_wizard.json', {'change_path': steps}) } }; @@ -2468,7 +2465,7 @@ async function steps_wizard (opts) { const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) const func = on[type] || fail func(data, type) - } + } } function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } function inject (data) { @@ -2480,10 +2477,7 @@ async function steps_wizard (opts) { function onvariables (data) { const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] variables = vars['change_path'] - if (!init) { - render_steps(variables); - init = true - } + render_steps(variables); } } From ba7ace4ee5c72069815a28de19d4c042e96f9681 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Fri, 27 Jun 2025 00:07:03 +0500 Subject: [PATCH 08/21] connect components --- .../quick_actions/quick_actions.js | 44 +++++- src/node_modules/steps_wizard/steps_wizard.js | 136 +++++++++++++++++- .../steps_wizard/steps_wizard.json | 2 +- src/node_modules/steps_wizard/stepswizard.css | 9 ++ 4 files changed, 184 insertions(+), 7 deletions(-) diff --git a/src/node_modules/quick_actions/quick_actions.js b/src/node_modules/quick_actions/quick_actions.js index 72b9e94..153404d 100644 --- a/src/node_modules/quick_actions/quick_actions.js +++ b/src/node_modules/quick_actions/quick_actions.js @@ -26,6 +26,12 @@ async function quick_actions(opts, protocol) {
/ +
@@ -42,6 +48,9 @@ async function quick_actions(opts, protocol) { const input_field = shadow.querySelector('.input-field') const submit_btn = shadow.querySelector('.submit-btn') const close_btn = shadow.querySelector('.close-btn') + const step_display = shadow.querySelector('.step-display') + const current_step = shadow.querySelector('.current-step') + const total_steps = shadow.querySelector('.total-step') const style = shadow.querySelector('style') const main = shadow.querySelector('.main') @@ -89,6 +98,12 @@ async function quick_actions(opts, protocol) { if (selected_action) { console.log('Selected action submitted:', selected_action) _.up({ type: 'action_submitted', data: selected_action }) + const nextStep = ++selected_action.current_step + current_step.textContent = nextStep + + if (nextStep > selected_action.total_steps) { + deactivate_input_field() + } } } function oninput(e) { @@ -117,7 +132,11 @@ async function quick_actions(opts, protocol) { if (selected_action) { slash_prefix.style.display = 'inline' command_text.style.display = 'inline' - command_text.textContent = `"${selected_action.action}"` + command_text.textContent = `#${selected_action.action}` + current_step.textContent = selected_action.current_step + total_steps.textContent = selected_action.total_steps + step_display.style.display = 'inline-flex' + input_field.style.display = 'none' submit_btn.style.display = 'flex' } else { @@ -125,6 +144,7 @@ async function quick_actions(opts, protocol) { command_text.style.display = 'none' input_field.style.display = 'block' submit_btn.style.display = 'none' + step_display.style.display = 'none' input_field.placeholder = 'Type to search actions...' } } @@ -367,6 +387,28 @@ function fallback_module() { width: 16px; height: 16px; } + .step-display { + display: inline-flex; + align-items: center; + gap: 2px; + margin-left: 8px; + background: #2d2d2d; + border: 1px solid #666; + border-radius: 4px; + padding: 1px 6px; + font-size: 12px; + color: #fff; + font-family: monospace; + } + .current-step { + color:#f0f0f0; + } + .step-separator { + color: #888; + } + .total-step { + color: #f0f0f0; + } ` } } diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 4a2828a..2f98412 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -2,6 +2,9 @@ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) +const quick_actions = require('quick_actions') +const actions = require('actions') + module.exports = steps_wizard async function steps_wizard (opts) { @@ -14,12 +17,17 @@ async function steps_wizard (opts) { } let variables = [] + let current_step = 1; + + let _ = {send_quick_actions: null} const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
-
+
+
+
@@ -27,14 +35,24 @@ async function steps_wizard (opts) { const style = shadow.querySelector('style') const steps_entries = shadow.querySelector('.steps-slot') + const quick_actions_placeholder = shadow.querySelector('.quick-actions') + const actions_placeholder = shadow.querySelector('.actions') const subs = await sdb.watch(onbatch) + const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) + quick_actions_placeholder.replaceWith(quick_actions_el) + + const actions_el = await actions(subs[1], actions_protocol) + actions_el.classList.add('hide') + actions_placeholder.replaceWith(actions_el) + return el function render_steps(steps) { if (!steps) return; + steps_entries.innerHTML = ''; steps.forEach((step, index) => { @@ -54,17 +72,28 @@ async function steps_wizard (opts) { btn.classList.add(`step-${status}`); btn.disabled = (status === 'disabled'); + if (accessible) { + current_step = index + 1; + } + btn.onclick = () => { if (!btn.disabled) { - step.is_completed = true - step.status = 'completed'; console.log('Clicked:', step); - drive.put('variables/steps_wizard.json', {'change_path': steps}) } }; steps_entries.appendChild(btn); }); + + if (_.send_quick_actions) { + _.send_quick_actions({ + type: 'update_steps', + data: { + current_step: current_step, + total_steps: steps.length + } + }); + } } @@ -98,15 +127,112 @@ async function steps_wizard (opts) { render_steps(variables); } + + function cleanup () { + const cleaned = variables.map(step => ({ + ...step, + is_completed: false + })); + + drive.put('variables/steps_wizard.json', { change_path: cleaned }); + } + // ---- Toggle Views ---- + function toggle_view(el, show) { + el.classList.toggle('hide', !show); + } + + function steps_toggle_view(display) { + toggle_view(steps_entries, display === 'block'); + } + + function actions_toggle_view(display) { + toggle_view(actions_el, display === 'block'); + } + + // ---- Protocols ---- + function actions_protocol (send) { + _.send_actions = send + return on + function on ({ type, data }) { + console.log('actions data', type, data) + _.send_quick_actions({ + type, + data: { + ...data, + current_step: current_step, + total_steps: variables.length + } + }) + + steps_toggle_view('block') + actions_toggle_view('hide') + } + } + + function quick_actions_protocol (send) { + _.send_quick_actions = send + return on + function on ({ type, data }) { + onmessage({type, data}) + } + } + + function onmessage ({ type, data }) { + if (type == 'display_actions') { + actions_toggle_view(data) + if (data === 'none') { + steps_toggle_view(data) + cleanup() + } + } else if (type == 'action_submitted') { + const step = variables[data.current_step - 1] + Object.assign(step, { + is_completed: true, + status: 'completed' + }) + drive.put('variables/steps_wizard.json', {change_path : variables}) + } + } + } + + function fallback_module () { return { - api: fallback_instance + api: fallback_instance, + _: { + 'quick_actions': { + $: '' + }, + 'actions': { + $: '' + }, + } } function fallback_instance () { return { + _: { + 'quick_actions': { + 0: '', + mapping: { + 'style': 'style', + 'icons': 'icons', + 'actions': 'actions', + 'hardcons': 'hardcons' + } + }, + 'actions': { + 0: '', + mapping: { + 'style': 'style', + 'actions': 'actions', + 'icons': 'icons', + 'hardcons': 'hardcons' + } + }, + }, drive: { 'style/': { 'stepswizard.css': { diff --git a/src/node_modules/steps_wizard/steps_wizard.json b/src/node_modules/steps_wizard/steps_wizard.json index 63a8b4a..6b5f5ef 100644 --- a/src/node_modules/steps_wizard/steps_wizard.json +++ b/src/node_modules/steps_wizard/steps_wizard.json @@ -1,5 +1,5 @@ {"change_path": [ {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "test", "status": "default"}, - {"name": "step 2", "type": "optional", "is_completed": false, "component": "test1", "status": "default" }, + {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "test1", "status": "default" }, {"name": "step 3", "type": "mandatory", "is_completed": false, "component": "test1", "status": "default" } ]} diff --git a/src/node_modules/steps_wizard/stepswizard.css b/src/node_modules/steps_wizard/stepswizard.css index 41a2396..9f7a23c 100644 --- a/src/node_modules/steps_wizard/stepswizard.css +++ b/src/node_modules/steps_wizard/stepswizard.css @@ -103,4 +103,13 @@ background-color: #444; border-color: #ccc; color: #ccc; +} + +/* Visibility */ +.hide { + display: none; +} + +.show { + display: block; } \ No newline at end of file From 0c5b38597a53efc41d148a8db3c0f83da33d3b05 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Fri, 27 Jun 2025 00:19:13 +0500 Subject: [PATCH 09/21] update svg --- src/node_modules/quick_actions/submit.svg | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node_modules/quick_actions/submit.svg b/src/node_modules/quick_actions/submit.svg index 033fa0d..5abe6cb 100644 --- a/src/node_modules/quick_actions/submit.svg +++ b/src/node_modules/quick_actions/submit.svg @@ -1,3 +1,4 @@ + From d7ede169ea41c9bc407a118999a2d230a8f013f2 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Fri, 27 Jun 2025 00:49:23 +0500 Subject: [PATCH 10/21] update bundle --- bundle.js | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 7 deletions(-) diff --git a/bundle.js b/bundle.js index 1fa55e7..be440b4 100644 --- a/bundle.js +++ b/bundle.js @@ -1416,6 +1416,12 @@ async function quick_actions(opts, protocol) {
/ +
@@ -1432,6 +1438,9 @@ async function quick_actions(opts, protocol) { const input_field = shadow.querySelector('.input-field') const submit_btn = shadow.querySelector('.submit-btn') const close_btn = shadow.querySelector('.close-btn') + const step_display = shadow.querySelector('.step-display') + const current_step = shadow.querySelector('.current-step') + const total_steps = shadow.querySelector('.total-step') const style = shadow.querySelector('style') const main = shadow.querySelector('.main') @@ -1479,6 +1488,12 @@ async function quick_actions(opts, protocol) { if (selected_action) { console.log('Selected action submitted:', selected_action) _.up({ type: 'action_submitted', data: selected_action }) + const nextStep = ++selected_action.current_step + current_step.textContent = nextStep + + if (nextStep > selected_action.total_steps) { + deactivate_input_field() + } } } function oninput(e) { @@ -1507,7 +1522,11 @@ async function quick_actions(opts, protocol) { if (selected_action) { slash_prefix.style.display = 'inline' command_text.style.display = 'inline' - command_text.textContent = `"${selected_action.action}"` + command_text.textContent = `#${selected_action.action}` + current_step.textContent = selected_action.current_step + total_steps.textContent = selected_action.total_steps + step_display.style.display = 'inline-flex' + input_field.style.display = 'none' submit_btn.style.display = 'flex' } else { @@ -1515,6 +1534,7 @@ async function quick_actions(opts, protocol) { command_text.style.display = 'none' input_field.style.display = 'block' submit_btn.style.display = 'none' + step_display.style.display = 'none' input_field.placeholder = 'Type to search actions...' } } @@ -1757,6 +1777,28 @@ function fallback_module() { width: 16px; height: 16px; } + .step-display { + display: inline-flex; + align-items: center; + gap: 2px; + margin-left: 8px; + background: #2d2d2d; + border: 1px solid #666; + border-radius: 4px; + padding: 1px 6px; + font-size: 12px; + color: #fff; + font-family: monospace; + } + .current-step { + color:#f0f0f0; + } + .step-separator { + color: #888; + } + .total-step { + color: #f0f0f0; + } ` } } @@ -2384,6 +2426,9 @@ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) +const quick_actions = require('quick_actions') +const actions = require('actions') + module.exports = steps_wizard async function steps_wizard (opts) { @@ -2396,12 +2441,17 @@ async function steps_wizard (opts) { } let variables = [] + let current_step = 1; + + let _ = {send_quick_actions: null} const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
-
+
+
+
@@ -2409,14 +2459,24 @@ async function steps_wizard (opts) { const style = shadow.querySelector('style') const steps_entries = shadow.querySelector('.steps-slot') + const quick_actions_placeholder = shadow.querySelector('.quick-actions') + const actions_placeholder = shadow.querySelector('.actions') const subs = await sdb.watch(onbatch) + const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) + quick_actions_placeholder.replaceWith(quick_actions_el) + + const actions_el = await actions(subs[1], actions_protocol) + actions_el.classList.add('hide') + actions_placeholder.replaceWith(actions_el) + return el function render_steps(steps) { if (!steps) return; + steps_entries.innerHTML = ''; steps.forEach((step, index) => { @@ -2436,17 +2496,28 @@ async function steps_wizard (opts) { btn.classList.add(`step-${status}`); btn.disabled = (status === 'disabled'); + if (accessible) { + current_step = index + 1; + } + btn.onclick = () => { if (!btn.disabled) { - step.is_completed = true - step.status = 'completed'; console.log('Clicked:', step); - drive.put('variables/steps_wizard.json', {'change_path': steps}) } }; steps_entries.appendChild(btn); }); + + if (_.send_quick_actions) { + _.send_quick_actions({ + type: 'update_steps', + data: { + current_step: current_step, + total_steps: steps.length + } + }); + } } @@ -2480,15 +2551,112 @@ async function steps_wizard (opts) { render_steps(variables); } + + function cleanup () { + const cleaned = variables.map(step => ({ + ...step, + is_completed: false + })); + + drive.put('variables/steps_wizard.json', { change_path: cleaned }); + } + // ---- Toggle Views ---- + function toggle_view(el, show) { + el.classList.toggle('hide', !show); + } + + function steps_toggle_view(display) { + toggle_view(steps_entries, display === 'block'); + } + + function actions_toggle_view(display) { + toggle_view(actions_el, display === 'block'); + } + + // ---- Protocols ---- + function actions_protocol (send) { + _.send_actions = send + return on + function on ({ type, data }) { + console.log('actions data', type, data) + _.send_quick_actions({ + type, + data: { + ...data, + current_step: current_step, + total_steps: variables.length + } + }) + + steps_toggle_view('block') + actions_toggle_view('hide') + } + } + + function quick_actions_protocol (send) { + _.send_quick_actions = send + return on + function on ({ type, data }) { + onmessage({type, data}) + } + } + + function onmessage ({ type, data }) { + if (type == 'display_actions') { + actions_toggle_view(data) + if (data === 'none') { + steps_toggle_view(data) + cleanup() + } + } else if (type == 'action_submitted') { + const step = variables[data.current_step - 1] + Object.assign(step, { + is_completed: true, + status: 'completed' + }) + drive.put('variables/steps_wizard.json', {change_path : variables}) + } + } + } + + function fallback_module () { return { - api: fallback_instance + api: fallback_instance, + _: { + 'quick_actions': { + $: '' + }, + 'actions': { + $: '' + }, + } } function fallback_instance () { return { + _: { + 'quick_actions': { + 0: '', + mapping: { + 'style': 'style', + 'icons': 'icons', + 'actions': 'actions', + 'hardcons': 'hardcons' + } + }, + 'actions': { + 0: '', + mapping: { + 'style': 'style', + 'actions': 'actions', + 'icons': 'icons', + 'hardcons': 'hardcons' + } + }, + }, drive: { 'style/': { 'stepswizard.css': { @@ -2506,7 +2674,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/steps_wizard/steps_wizard.js") -},{"STATE":1}],11:[function(require,module,exports){ +},{"STATE":1,"actions":3,"quick_actions":7}],11:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) From 1452494cda5d8f5da42d75b81751e538511de9b9 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 5 Jul 2025 17:37:06 +0500 Subject: [PATCH 11/21] restrucutre steps wizard --- src/node_modules/form_input.js | 119 +++++++ src/node_modules/program/package.json | 5 + src/node_modules/program/program.css | 12 + src/node_modules/program/program.js | 305 ++++++++++++++++++ src/node_modules/program/program.json | 5 + .../quick_actions/quick_actions.js | 13 +- src/node_modules/steps_wizard/steps_wizard.js | 201 +++--------- .../steps_wizard/steps_wizard.json | 6 +- web/page.js | 14 +- 9 files changed, 505 insertions(+), 175 deletions(-) create mode 100644 src/node_modules/form_input.js create mode 100644 src/node_modules/program/package.json create mode 100644 src/node_modules/program/program.css create mode 100644 src/node_modules/program/program.js create mode 100644 src/node_modules/program/program.json diff --git a/src/node_modules/form_input.js b/src/node_modules/form_input.js new file mode 100644 index 0000000..44d34f8 --- /dev/null +++ b/src/node_modules/form_input.js @@ -0,0 +1,119 @@ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +module.exports = form_input +async function form_input (opts, protocol) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + + const on = { + style: inject, + } + + let current_step = null + + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
+ +
+ ` + const style = shadow.querySelector('style') + + input_field_el = shadow.querySelector('.input-field') + + input_field_el.oninput = function () { + if (this.value.length >= 10) { + _.up({ + type: 'action_submitted', + data: { + value: this.value, + index: current_step?.index || 0 + } + }) + console.log('mark_as_complete') + } + } + + const subs = await sdb.watch(onbatch) + + + return el + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } + + function inject (data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onmessage ({ type, data }) { + console.log('message from form_input', type, data) + if (type === 'step_data') { + current_step = data + input_field_el.value = data?.data || '' + } + } + +} +function fallback_module () { + return { + api: fallback_instance, + } + function fallback_instance () { + return { + drive: { + 'style/': { + 'theme.css': { + raw: ` + .input-display { + background: #131315; + border-radius: 16px; + border: 1px solid #3c3c3c; + display: flex; + flex: 1; + align-items: center; + padding: 0 12px; + min-height: 32px; + } + .input-display:focus-within { + border-color: #4285f4; + background: #1a1a1c; + } + .input-field { + flex: 1; + min-height: 32px; + background: transparent; + border: none; + color: #e8eaed; + padding: 0 12px; + font-size: 14px; + outline: none; + } + .input-field::placeholder { + color: #a6a6a6; + } + ` + } + } + } + } + } +} diff --git a/src/node_modules/program/package.json b/src/node_modules/program/package.json new file mode 100644 index 0000000..f14c75f --- /dev/null +++ b/src/node_modules/program/package.json @@ -0,0 +1,5 @@ +{ + "name": "program", + "main": "program.js" + } + \ No newline at end of file diff --git a/src/node_modules/program/program.css b/src/node_modules/program/program.css new file mode 100644 index 0000000..f0d939f --- /dev/null +++ b/src/node_modules/program/program.css @@ -0,0 +1,12 @@ +.main { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + background: #131315; +} + +/* Visibility */ +.hide { + display: none; +} diff --git a/src/node_modules/program/program.js b/src/node_modules/program/program.js new file mode 100644 index 0000000..54b779c --- /dev/null +++ b/src/node_modules/program/program.js @@ -0,0 +1,305 @@ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +const quick_actions = require('quick_actions') +const actions = require('actions') +const form_input = require('form_input') +const steps_wizard = require('steps_wizard') + + +module.exports = program + +async function program (opts) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + + const on = { + style: inject, + variables: onvariables, + } + + let variables = [] + + let _ = { + send_quick_actions: null, + send_actions: null, + send_form_input: null, + send_steps_wizard: null + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
+ + + + +
+ + ` + + const style = shadow.querySelector('style') + const steps_wizard_placeholder = shadow.querySelector('steps-wizard') + const quick_actions_placeholder = shadow.querySelector('quick-actions') + const actions_placeholder = shadow.querySelector('actions') + const form_input_placeholder = shadow.querySelector('form-input') + + const subs = await sdb.watch(onbatch) + + + + const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) + quick_actions_placeholder.replaceWith(quick_actions_el) + + const actions_el = await actions(subs[1], actions_protocol) + actions_el.classList.add('hide') + actions_placeholder.replaceWith(actions_el) + + const steps_wizard_el = await steps_wizard(subs[2], steps_wizard_protocol) + steps_wizard_el.classList.add('hide') + steps_wizard_placeholder.replaceWith(steps_wizard_el) + + let form_input_el = await form_input(subs[3], form_input_protocol) + form_input_el.classList.add('hide') + form_input_placeholder.replaceWith(form_input_el) + + + return el + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } + function inject (data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onvariables (data) { + const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] + variables = vars['change_path'] + if (_.send_steps_wizard) + _.send_steps_wizard({type: "init_data", data: variables}) + } + + + // ---- Toggle Views ---- + function toggle_view(el, show) { + el.classList.toggle('hide', !show) + } + + function steps_toggle_view(display) { + toggle_view(steps_wizard_el, display === 'block') + } + + function form_input_toggle_view(display) { + toggle_view(form_input_el, display === 'block') + } + + function actions_toggle_view(display) { + toggle_view(actions_el, display === 'block') + } + + // ---- Protocols ---- + function form_input_protocol (send) { + _.send_form_input = send + return on + function on ({ type, data }) { + console.log('form input data', type, data) + if (type == 'action_submitted') { + const step = variables[data?.index] + Object.assign(step, { + is_completed: true, + status: 'completed', + data: data?.value + }) + console.log(variables) + drive.put('variables/program.json', {change_path : variables}) + } + } + } + + function steps_wizard_protocol(send) { + _.send_steps_wizard = send + return on + function on ({ type, data }) { + console.log('step wizard data', type, data) + if (type === 'step_clicked') { + _.send_quick_actions({ + type: 'update_steps', + data: { + current_step: data?.index+1, + total_steps: data?.total_steps + } + }); + render_form_component(data.component) + _.send_form_input({ type: 'step_data', data }) + } + } + } + + async function render_form_component(component_name) { + let index = get_form_input_component_index(component_name) + + const component_fn = component_modules[component_name] + if (!component_fn) throw new Error(`Unknown component "${component_name}"`) + + form_input_el = await component_fn(subs[index], form_input_protocol) + form_input_placeholder.replaceWith(form_input_el) + } + + + function get_form_input_component_index(component) { + const { _: components } = fallback_module() + return Object.keys(components).indexOf(component) + } + + + function actions_protocol (send) { + _.send_actions = send + return on + function on ({ type, data }) { + console.log('actions data', type, data) + _.send_quick_actions({ + type, + data: { + ...data, + total_steps: variables.length + } + }) + + _.send_steps_wizard({type: 'init_data', data: variables}) + steps_toggle_view('block') + + form_input_toggle_view('block') + _.send_form_input({ type: 'step_data', data }) + actions_toggle_view('none') + } + } + + function quick_actions_protocol (send) { + _.send_quick_actions = send + return on + function on ({ type, data }) { + on_quick_actions_message({type, data}) + } + } + + function on_quick_actions_message ({ type, data }) { + if (type == 'display_actions') { + actions_toggle_view(data) + if (data === 'none') { + steps_toggle_view(data) + form_input_toggle_view(data) + cleanup() + } + } else if (type == 'action_submitted') { + console.log(variables) + is_completed = variables[data?.total_steps - 1]?.is_completed + if (is_completed) { + alert(JSON.stringify(variables.map(step => step.data), null, 2)) + if (_.send_quick_actions) { + _.send_quick_actions({ + type: 'deactivate_input_field' + }) + } + } + } + } + + + function cleanup () { + const cleaned = variables.map(step => ({ + ...step, + is_completed: false, + data: '' + })); + + drive.put('variables/program.json', { change_path: cleaned }) + } + + +} + +const component_modules = { + 'form_input': form_input, +}; + +function fallback_module () { + return { + api: fallback_instance, + _: { + 'quick_actions': { + $: '' + }, + 'actions': { + $: '' + }, + 'steps_wizard': { + $: '' + }, + 'form_input': { + $: '' + } + } + } + + function fallback_instance () { + return { + _: { + 'quick_actions': { + 0: '', + mapping: { + 'style': 'style', + 'icons': 'icons', + 'actions': 'actions', + 'hardcons': 'hardcons' + } + }, + 'actions': { + 0: '', + mapping: { + 'style': 'style', + 'actions': 'actions', + 'icons': 'icons', + 'hardcons': 'hardcons' + } + }, + 'steps_wizard': { + 0: '', + mapping: { + 'style': 'style', + 'variables': 'variables' + } + }, + 'form_input': { + 0: '', + mapping: { + 'style': 'style', + } + } + }, + drive: { + 'style/': { + 'program.css': { + '$ref': 'program.css' + } + }, + 'variables/': { + 'program.json': { + '$ref': 'program.json' + } + }, + } + } + } +} diff --git a/src/node_modules/program/program.json b/src/node_modules/program/program.json new file mode 100644 index 0000000..f37c3a3 --- /dev/null +++ b/src/node_modules/program/program.json @@ -0,0 +1,5 @@ +{"change_path": [ + {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {"name": "step 3", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} +]} diff --git a/src/node_modules/quick_actions/quick_actions.js b/src/node_modules/quick_actions/quick_actions.js index 153404d..88dfc24 100644 --- a/src/node_modules/quick_actions/quick_actions.js +++ b/src/node_modules/quick_actions/quick_actions.js @@ -80,6 +80,11 @@ async function quick_actions(opts, protocol) { function onmessage ({ type, data }) { if (type === 'selected_action') { select_action(data) + } else if (type === 'update_steps') { + current_step.textContent = data.current_step + selected_action.current_step = data.current_step + } else if (type === 'deactivate_input_field') { + deactivate_input_field() } } function activate_input_field() { @@ -98,12 +103,6 @@ async function quick_actions(opts, protocol) { if (selected_action) { console.log('Selected action submitted:', selected_action) _.up({ type: 'action_submitted', data: selected_action }) - const nextStep = ++selected_action.current_step - current_step.textContent = nextStep - - if (nextStep > selected_action.total_steps) { - deactivate_input_field() - } } } function oninput(e) { @@ -133,7 +132,7 @@ async function quick_actions(opts, protocol) { slash_prefix.style.display = 'inline' command_text.style.display = 'inline' command_text.textContent = `#${selected_action.action}` - current_step.textContent = selected_action.current_step + current_step.textContent = selected_action?.current_step || 1 total_steps.textContent = selected_action.total_steps step_display.style.display = 'inline-flex' diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 2f98412..e0da3c8 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -2,32 +2,29 @@ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const quick_actions = require('quick_actions') -const actions = require('actions') - module.exports = steps_wizard -async function steps_wizard (opts) { +async function steps_wizard (opts, protocol) { const { id, sdb } = await get(opts.sid) const {drive} = sdb const on = { - style: inject, - variables: onvariables, + style: inject } let variables = [] - let current_step = 1; - let _ = {send_quick_actions: null} + let _ = null + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
-
-
-
+
@@ -35,20 +32,19 @@ async function steps_wizard (opts) { const style = shadow.querySelector('style') const steps_entries = shadow.querySelector('.steps-slot') - const quick_actions_placeholder = shadow.querySelector('.quick-actions') - const actions_placeholder = shadow.querySelector('.actions') - + const subs = await sdb.watch(onbatch) - const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) - quick_actions_placeholder.replaceWith(quick_actions_el) - - const actions_el = await actions(subs[1], actions_protocol) - actions_el.classList.add('hide') - actions_placeholder.replaceWith(actions_el) - return el + function onmessage ({ type, data }) { + console.log('steps_ data', type, data) + if (type === 'init_data') { + variables = data + render_steps(variables) + } + } + function render_steps(steps) { if (!steps) return; @@ -56,55 +52,42 @@ async function steps_wizard (opts) { steps_entries.innerHTML = ''; steps.forEach((step, index) => { - const btn = document.createElement('button'); - btn.className = 'step-button'; - btn.textContent = step.name + (step.type === 'optional' ? ' *' : ''); - btn.setAttribute('data-step', index + 1); - - const accessible = can_access(index, steps); + const btn = document.createElement('button') + btn.className = 'step-button' + btn.textContent = step.name + (step.type === 'optional' ? ' *' : '') + btn.setAttribute('data-step', index + 1) - let status = 'default'; - if (!accessible) status = 'disabled'; - else if (step.is_completed) status = 'completed'; - else if (step.status === 'error') status = 'error'; - else if (step.type === 'optional') status = 'optional'; + const accessible = can_access(index, steps) - btn.classList.add(`step-${status}`); - btn.disabled = (status === 'disabled'); + let status = 'default' + if (!accessible) status = 'disabled' + else if (step.is_completed) status = 'completed' + else if (step.status === 'error') status = 'error' + else if (step.type === 'optional') status = 'optional' - if (accessible) { - current_step = index + 1; - } + btn.classList.add(`step-${status}`) + btn.disabled = (status === 'disabled') - btn.onclick = () => { + btn.onclick = async () => { if (!btn.disabled) { - console.log('Clicked:', step); + console.log('Clicked:', step) + _.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) } }; - steps_entries.appendChild(btn); + steps_entries.appendChild(btn) }); - - if (_.send_quick_actions) { - _.send_quick_actions({ - type: 'update_steps', - data: { - current_step: current_step, - total_steps: steps.length - } - }); - } } function can_access(index, steps) { for (let i = 0; i < index; i++) { if (!steps[i].is_completed && steps[i].type !== 'optional') { - return false; + return false } } - return true; + return true } async function onbatch(batch) { @@ -120,130 +103,22 @@ async function steps_wizard (opts) { return document.createElement('style').textContent = data[0] })()) } - - function onvariables (data) { - const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] - variables = vars['change_path'] - render_steps(variables); - } - - - function cleanup () { - const cleaned = variables.map(step => ({ - ...step, - is_completed: false - })); - - drive.put('variables/steps_wizard.json', { change_path: cleaned }); - } - // ---- Toggle Views ---- - function toggle_view(el, show) { - el.classList.toggle('hide', !show); - } - - function steps_toggle_view(display) { - toggle_view(steps_entries, display === 'block'); - } - - function actions_toggle_view(display) { - toggle_view(actions_el, display === 'block'); - } - - // ---- Protocols ---- - function actions_protocol (send) { - _.send_actions = send - return on - function on ({ type, data }) { - console.log('actions data', type, data) - _.send_quick_actions({ - type, - data: { - ...data, - current_step: current_step, - total_steps: variables.length - } - }) - - steps_toggle_view('block') - actions_toggle_view('hide') - } - } - - function quick_actions_protocol (send) { - _.send_quick_actions = send - return on - function on ({ type, data }) { - onmessage({type, data}) - } - } - - function onmessage ({ type, data }) { - if (type == 'display_actions') { - actions_toggle_view(data) - if (data === 'none') { - steps_toggle_view(data) - cleanup() - } - } else if (type == 'action_submitted') { - const step = variables[data.current_step - 1] - Object.assign(step, { - is_completed: true, - status: 'completed' - }) - drive.put('variables/steps_wizard.json', {change_path : variables}) - } - } - + } - - function fallback_module () { return { - api: fallback_instance, - _: { - 'quick_actions': { - $: '' - }, - 'actions': { - $: '' - }, - } + api: fallback_instance } function fallback_instance () { return { - _: { - 'quick_actions': { - 0: '', - mapping: { - 'style': 'style', - 'icons': 'icons', - 'actions': 'actions', - 'hardcons': 'hardcons' - } - }, - 'actions': { - 0: '', - mapping: { - 'style': 'style', - 'actions': 'actions', - 'icons': 'icons', - 'hardcons': 'hardcons' - } - }, - }, drive: { 'style/': { 'stepswizard.css': { '$ref': 'stepswizard.css' } - }, - 'variables/': { - 'steps_wizard.json': { - '$ref': 'steps_wizard.json' - } - }, + } } } } diff --git a/src/node_modules/steps_wizard/steps_wizard.json b/src/node_modules/steps_wizard/steps_wizard.json index 6b5f5ef..f37c3a3 100644 --- a/src/node_modules/steps_wizard/steps_wizard.json +++ b/src/node_modules/steps_wizard/steps_wizard.json @@ -1,5 +1,5 @@ {"change_path": [ - {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "test", "status": "default"}, - {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "test1", "status": "default" }, - {"name": "step 3", "type": "mandatory", "is_completed": false, "component": "test1", "status": "default" } + {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {"name": "step 3", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} ]} diff --git a/web/page.js b/web/page.js index d616ddd..3b04f0d 100644 --- a/web/page.js +++ b/web/page.js @@ -19,6 +19,7 @@ const task_manager = require('../src/node_modules/task_manager') const quick_actions = require('../src/node_modules/quick_actions') const graph_explorer = require('../src/node_modules/graph_explorer') const editor = require('../src/node_modules/quick_editor') +const program = require('../src/node_modules/program') const steps_wizard = require('../src/node_modules/steps_wizard') const imports = { @@ -34,6 +35,7 @@ const imports = { task_manager, quick_actions, graph_explorer, + program, steps_wizard, } config().then(() => boot({ sid: '' })) @@ -295,7 +297,8 @@ function fallback_module () { '../src/node_modules/task_manager', '../src/node_modules/quick_actions', '../src/node_modules/graph_explorer', - '../src/node_modules/steps_wizard' + '../src/node_modules/program', + '../src/node_modules/steps_wizard', ] const subs = {} names.forEach(subgen) @@ -309,7 +312,7 @@ function fallback_module () { 'style': 'style' } } - subs['../src/node_modules/steps_wizard'] = { + subs['../src/node_modules/program'] = { $: '', 0: '', mapping: { @@ -317,6 +320,13 @@ function fallback_module () { 'style': 'style' } } + subs['../src/node_modules/steps_wizard'] = { + $: '', + 0: '', + mapping: { + 'style': 'style' + } + } subs['../src/node_modules/tabsbar'] = { $: '', 0: '', From 91c3bd1e4044e17ef50a8aad937ef7c025e35e57 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 5 Jul 2025 17:37:56 +0500 Subject: [PATCH 12/21] remove json --- src/node_modules/steps_wizard/steps_wizard.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/node_modules/steps_wizard/steps_wizard.json diff --git a/src/node_modules/steps_wizard/steps_wizard.json b/src/node_modules/steps_wizard/steps_wizard.json deleted file mode 100644 index f37c3a3..0000000 --- a/src/node_modules/steps_wizard/steps_wizard.json +++ /dev/null @@ -1,5 +0,0 @@ -{"change_path": [ - {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, - {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, - {"name": "step 3", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} -]} From cf372ee540f4624d115af15b1ebd4b93dda4e4d3 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 5 Jul 2025 17:43:35 +0500 Subject: [PATCH 13/21] demo step --- src/node_modules/steps_wizard/steps_wizard.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index e0da3c8..7eafd11 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -35,6 +35,12 @@ async function steps_wizard (opts, protocol) { const subs = await sdb.watch(onbatch) + // for demo purpose + render_steps([ + {name: "Optional Step", "type": "optional", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {name: "Step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} + ]) + return el function onmessage ({ type, data }) { @@ -71,7 +77,8 @@ async function steps_wizard (opts, protocol) { btn.onclick = async () => { if (!btn.disabled) { console.log('Clicked:', step) - _.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) + if (_.up) + _.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) } }; From 48525ebdb22ec1914b4026a8a381b709a5cd31ee Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 5 Jul 2025 19:11:18 +0500 Subject: [PATCH 14/21] add dynamic component handling --- src/node_modules/form_input.js | 7 +- src/node_modules/input_test.js | 124 ++++++++++ src/node_modules/program/program.js | 217 ++++++++---------- src/node_modules/program/program.json | 2 +- src/node_modules/steps_wizard/steps_wizard.js | 3 +- 5 files changed, 233 insertions(+), 120 deletions(-) create mode 100644 src/node_modules/input_test.js diff --git a/src/node_modules/form_input.js b/src/node_modules/form_input.js index 44d34f8..6c463d6 100644 --- a/src/node_modules/form_input.js +++ b/src/node_modules/form_input.js @@ -22,13 +22,15 @@ async function form_input (opts, protocol) { const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
- +
+ +
` const style = shadow.querySelector('style') - input_field_el = shadow.querySelector('.input-field') + const input_field_el = shadow.querySelector('.input-field') input_field_el.oninput = function () { if (this.value.length >= 10) { @@ -68,6 +70,7 @@ async function form_input (opts, protocol) { console.log('message from form_input', type, data) if (type === 'step_data') { current_step = data + console.log('message from form_input', input_field_el, input_field_el.value) input_field_el.value = data?.data || '' } } diff --git a/src/node_modules/input_test.js b/src/node_modules/input_test.js new file mode 100644 index 0000000..2b0bd2a --- /dev/null +++ b/src/node_modules/input_test.js @@ -0,0 +1,124 @@ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +module.exports = input_test +async function input_test (opts, protocol) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + + const on = { + style: inject, + } + + let current_step = null + + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
Testing 2nd Type
+
+ +
+ ` + const style = shadow.querySelector('style') + + const input_field_el = shadow.querySelector('.input-field') + + input_field_el.oninput = function () { + if (this.value.length >= 10) { + _.up({ + type: 'action_submitted', + data: { + value: this.value, + index: current_step?.index || 0 + } + }) + console.log('mark_as_complete') + } + } + + const subs = await sdb.watch(onbatch) + + + return el + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } + + function inject (data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onmessage ({ type, data }) { + console.log('message from input_test', type, data) + if (type === 'step_data') { + current_step = data + input_field_el.value = data?.data || '' + } + } + +} +function fallback_module () { + return { + api: fallback_instance, + } + function fallback_instance () { + return { + drive: { + 'style/': { + 'theme.css': { + raw: ` + .title { + color: #e8eaed; + font-size: 18px; + } + .input-display { + background: #131315; + border-radius: 16px; + border: 1px solid #3c3c3c; + display: flex; + flex: 1; + align-items: center; + padding: 0 12px; + min-height: 32px; + } + .input-display:focus-within { + border-color: #4285f4; + background: #1a1a1c; + } + .input-field { + flex: 1; + min-height: 32px; + background: transparent; + border: none; + color: #e8eaed; + padding: 0 12px; + font-size: 14px; + outline: none; + } + .input-field::placeholder { + color: #a6a6a6; + } + ` + } + } + } + } + } +} diff --git a/src/node_modules/program/program.js b/src/node_modules/program/program.js index 54b779c..0f869ee 100644 --- a/src/node_modules/program/program.js +++ b/src/node_modules/program/program.js @@ -6,14 +6,20 @@ const quick_actions = require('quick_actions') const actions = require('actions') const form_input = require('form_input') const steps_wizard = require('steps_wizard') +const input_test = require('input_test') +const component_modules = { + 'form_input': form_input, + 'input_test': input_test + // Add more form input components here if needed +} module.exports = program -async function program (opts) { +async function program(opts) { const { id, sdb } = await get(opts.sid) - const {drive} = sdb - + const { drive } = sdb + const on = { style: inject, variables: onvariables, @@ -21,24 +27,23 @@ async function program (opts) { let variables = [] - let _ = { + const _ = { send_quick_actions: null, send_actions: null, - send_form_input: null, + send_form_input: {}, send_steps_wizard: null } const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = ` -
- - - - -
- +
+ + + + +
+ ` const style = shadow.querySelector('style') @@ -49,8 +54,6 @@ async function program (opts) { const subs = await sdb.watch(onbatch) - - const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) quick_actions_placeholder.replaceWith(quick_actions_el) @@ -62,37 +65,46 @@ async function program (opts) { steps_wizard_el.classList.add('hide') steps_wizard_placeholder.replaceWith(steps_wizard_el) - let form_input_el = await form_input(subs[3], form_input_protocol) - form_input_el.classList.add('hide') - form_input_placeholder.replaceWith(form_input_el) + const form_input_elements = {} + for (const [component_name, component_fn] of Object.entries(component_modules)) { + const index = get_form_input_component_index(component_name) + const el = await component_fn(subs[index], form_input_protocol(component_name)) + el.classList.add('hide') + form_input_elements[component_name] = el + form_input_placeholder.parentNode.insertBefore(el, form_input_placeholder) + } + + form_input_placeholder.remove() return el - + + // --- Internal Functions --- async function onbatch(batch) { - for (const { type, paths } of batch){ + for (const { type, paths } of batch) { const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) const func = on[type] || fail func(data, type) } } - function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } - function inject (data) { + function fail(data, type) { + throw new Error('invalid message', { cause: { data, type } }) + } + + function inject(data) { style.replaceChildren((() => { return document.createElement('style').textContent = data[0] })()) } - function onvariables (data) { + function onvariables(data) { const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] - variables = vars['change_path'] + variables = vars['change_path'] if (_.send_steps_wizard) - _.send_steps_wizard({type: "init_data", data: variables}) + _.send_steps_wizard({ type: "init_data", data: variables }) } - - // ---- Toggle Views ---- function toggle_view(el, show) { el.classList.toggle('hide', !show) } @@ -100,30 +112,24 @@ async function program (opts) { function steps_toggle_view(display) { toggle_view(steps_wizard_el, display === 'block') } - - function form_input_toggle_view(display) { - toggle_view(form_input_el, display === 'block') - } function actions_toggle_view(display) { toggle_view(actions_el, display === 'block') } - // ---- Protocols ---- - function form_input_protocol (send) { - _.send_form_input = send - return on - function on ({ type, data }) { - console.log('form input data', type, data) - if (type == 'action_submitted') { - const step = variables[data?.index] - Object.assign(step, { - is_completed: true, - status: 'completed', - data: data?.value - }) - console.log(variables) - drive.put('variables/program.json', {change_path : variables}) + function form_input_protocol(component_name) { + return function (send) { + _.send_form_input[component_name] = send + return function on({ type, data }) { + if (type === 'action_submitted') { + const step = variables[data?.index] + Object.assign(step, { + is_completed: true, + status: 'completed', + data: data?.value + }) + drive.put('variables/program.json', { change_path: variables }) + } } } } @@ -131,129 +137,108 @@ async function program (opts) { function steps_wizard_protocol(send) { _.send_steps_wizard = send return on - function on ({ type, data }) { - console.log('step wizard data', type, data) + function on({ type, data }) { if (type === 'step_clicked') { + console.log('step clicked data---------', type, data) _.send_quick_actions({ type: 'update_steps', data: { - current_step: data?.index+1, + current_step: data?.index + 1, total_steps: data?.total_steps } - }); + }) + render_form_component(data.component) - _.send_form_input({ type: 'step_data', data }) + const send = _.send_form_input[data.component] + if (send) send({ type: 'step_data', data }) } } } - async function render_form_component(component_name) { - let index = get_form_input_component_index(component_name) - - const component_fn = component_modules[component_name] - if (!component_fn) throw new Error(`Unknown component "${component_name}"`) - - form_input_el = await component_fn(subs[index], form_input_protocol) - form_input_placeholder.replaceWith(form_input_el) + function render_form_component(component_name) { + for (const name in form_input_elements) { + toggle_view(form_input_elements[name], name === component_name) + } } - function get_form_input_component_index(component) { const { _: components } = fallback_module() return Object.keys(components).indexOf(component) } - - function actions_protocol (send) { + function actions_protocol(send) { _.send_actions = send return on - function on ({ type, data }) { - console.log('actions data', type, data) + function on({ type, data }) { _.send_quick_actions({ type, data: { - ...data, - total_steps: variables.length + ...data, + total_steps: variables.length } }) - - _.send_steps_wizard({type: 'init_data', data: variables}) + _.send_steps_wizard({ type: 'init_data', data: variables }) steps_toggle_view('block') - form_input_toggle_view('block') - _.send_form_input({ type: 'step_data', data }) + // render_form_component(data.component) + // const send = _.send_form_input[data.component] + // if (send) send({ type: 'step_data', data }) + actions_toggle_view('none') } } - function quick_actions_protocol (send) { + function quick_actions_protocol(send) { _.send_quick_actions = send return on - function on ({ type, data }) { - on_quick_actions_message({type, data}) + function on({ type, data }) { + on_quick_actions_message({ type, data }) } } - - function on_quick_actions_message ({ type, data }) { + + function on_quick_actions_message({ type, data }) { if (type == 'display_actions') { actions_toggle_view(data) if (data === 'none') { steps_toggle_view(data) - form_input_toggle_view(data) + for (const el of Object.values(form_input_elements)) { + toggle_view(el, false) + } cleanup() } } else if (type == 'action_submitted') { - console.log(variables) - is_completed = variables[data?.total_steps - 1]?.is_completed + const is_completed = variables[data?.total_steps - 1]?.is_completed if (is_completed) { alert(JSON.stringify(variables.map(step => step.data), null, 2)) - if (_.send_quick_actions) { - _.send_quick_actions({ - type: 'deactivate_input_field' - }) - } + _.send_quick_actions?.({ type: 'deactivate_input_field' }) } } } - - function cleanup () { + function cleanup() { const cleaned = variables.map(step => ({ ...step, is_completed: false, data: '' - })); - + })) drive.put('variables/program.json', { change_path: cleaned }) } - - } -const component_modules = { - 'form_input': form_input, -}; - -function fallback_module () { +// --- Fallback Module --- +function fallback_module() { return { api: fallback_instance, _: { - 'quick_actions': { - $: '' - }, - 'actions': { - $: '' - }, - 'steps_wizard': { - $: '' - }, - 'form_input': { - $: '' - } + 'quick_actions': { $: '' }, + 'actions': { $: '' }, + 'steps_wizard': { $: '' }, + 'form_input': { $: '' }, + 'input_test': { $: '' } } } - function fallback_instance () { + function fallback_instance() { return { _: { 'quick_actions': { @@ -284,21 +269,23 @@ function fallback_module () { 'form_input': { 0: '', mapping: { - 'style': 'style', + 'style': 'style' + } + }, + 'input_test': { + 0: '', + mapping: { + 'style': 'style' } } }, drive: { 'style/': { - 'program.css': { - '$ref': 'program.css' - } + 'program.css': { '$ref': 'program.css' } }, 'variables/': { - 'program.json': { - '$ref': 'program.json' - } - }, + 'program.json': { '$ref': 'program.json' } + } } } } diff --git a/src/node_modules/program/program.json b/src/node_modules/program/program.json index f37c3a3..dedfd65 100644 --- a/src/node_modules/program/program.json +++ b/src/node_modules/program/program.json @@ -1,5 +1,5 @@ {"change_path": [ {"name": "select an element", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, - {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {"name": "step 2", "type": "mandatory", "is_completed": false, "component": "input_test", "status": "default", "data": ""}, {"name": "step 3", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} ]} diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 7eafd11..798efcc 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -77,8 +77,7 @@ async function steps_wizard (opts, protocol) { btn.onclick = async () => { if (!btn.disabled) { console.log('Clicked:', step) - if (_.up) - _.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) + _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) } }; From db34012a501e43b08c8ff8dc987194838d2ccd03 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 5 Jul 2025 19:12:01 +0500 Subject: [PATCH 15/21] update bundle --- bundle.js | 812 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 626 insertions(+), 186 deletions(-) diff --git a/bundle.js b/bundle.js index be440b4..7ce0ab0 100644 --- a/bundle.js +++ b/bundle.js @@ -175,7 +175,7 @@ function fallback_module() { } } }).call(this)}).call(this,"/src/node_modules/action_bar/action_bar.js") -},{"STATE":1,"quick_actions":7}],3:[function(require,module,exports){ +},{"STATE":1,"quick_actions":10}],3:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -822,6 +822,132 @@ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) +module.exports = form_input +async function form_input (opts, protocol) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + + const on = { + style: inject, + } + + let current_step = null + + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
+
+ +
+
+ ` + const style = shadow.querySelector('style') + + const input_field_el = shadow.querySelector('.input-field') + + input_field_el.oninput = function () { + if (this.value.length >= 10) { + _.up({ + type: 'action_submitted', + data: { + value: this.value, + index: current_step?.index || 0 + } + }) + console.log('mark_as_complete') + } + } + + const subs = await sdb.watch(onbatch) + + + return el + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } + + function inject (data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onmessage ({ type, data }) { + console.log('message from form_input', type, data) + if (type === 'step_data') { + current_step = data + console.log('message from form_input', input_field_el, input_field_el.value) + input_field_el.value = data?.data || '' + } + } + +} +function fallback_module () { + return { + api: fallback_instance, + } + function fallback_instance () { + return { + drive: { + 'style/': { + 'theme.css': { + raw: ` + .input-display { + background: #131315; + border-radius: 16px; + border: 1px solid #3c3c3c; + display: flex; + flex: 1; + align-items: center; + padding: 0 12px; + min-height: 32px; + } + .input-display:focus-within { + border-color: #4285f4; + background: #1a1a1c; + } + .input-field { + flex: 1; + min-height: 32px; + background: transparent; + border: none; + color: #e8eaed; + padding: 0 12px; + font-size: 14px; + outline: none; + } + .input-field::placeholder { + color: #a6a6a6; + } + ` + } + } + } + } + } +} + +}).call(this)}).call(this,"/src/node_modules/form_input.js") +},{"STATE":1}],6:[function(require,module,exports){ +(function (__filename){(function (){ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + module.exports = component async function component (opts, protocol) { @@ -1131,7 +1257,135 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/graph_explorer/graph_explorer.js") -},{"STATE":1}],6:[function(require,module,exports){ +},{"STATE":1}],7:[function(require,module,exports){ +(function (__filename){(function (){ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +module.exports = input_test +async function input_test (opts, protocol) { + const { id, sdb } = await get(opts.sid) + const {drive} = sdb + + const on = { + style: inject, + } + + let current_step = null + + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
Testing 2nd Type
+
+ +
+ ` + const style = shadow.querySelector('style') + + const input_field_el = shadow.querySelector('.input-field') + + input_field_el.oninput = function () { + if (this.value.length >= 10) { + _.up({ + type: 'action_submitted', + data: { + value: this.value, + index: current_step?.index || 0 + } + }) + console.log('mark_as_complete') + } + } + + const subs = await sdb.watch(onbatch) + + + return el + + async function onbatch(batch) { + for (const { type, paths } of batch){ + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + + function fail(data, type) { throw new Error('invalid message', { cause: { data, type } }) } + + function inject (data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onmessage ({ type, data }) { + console.log('message from input_test', type, data) + if (type === 'step_data') { + current_step = data + input_field_el.value = data?.data || '' + } + } + +} +function fallback_module () { + return { + api: fallback_instance, + } + function fallback_instance () { + return { + drive: { + 'style/': { + 'theme.css': { + raw: ` + .title { + color: #e8eaed; + font-size: 18px; + } + .input-display { + background: #131315; + border-radius: 16px; + border: 1px solid #3c3c3c; + display: flex; + flex: 1; + align-items: center; + padding: 0 12px; + min-height: 32px; + } + .input-display:focus-within { + border-color: #4285f4; + background: #1a1a1c; + } + .input-field { + flex: 1; + min-height: 32px; + background: transparent; + border: none; + color: #e8eaed; + padding: 0 12px; + font-size: 14px; + outline: none; + } + .input-field::placeholder { + color: #a6a6a6; + } + ` + } + } + } + } + } +} + +}).call(this)}).call(this,"/src/node_modules/input_test.js") +},{"STATE":1}],8:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -1386,7 +1640,303 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/menu.js") -},{"STATE":1}],7:[function(require,module,exports){ +},{"STATE":1}],9:[function(require,module,exports){ +(function (__filename){(function (){ +const STATE = require('STATE') +const statedb = STATE(__filename) +const { sdb, get } = statedb(fallback_module) + +const quick_actions = require('quick_actions') +const actions = require('actions') +const form_input = require('form_input') +const steps_wizard = require('steps_wizard') +const input_test = require('input_test') + +const component_modules = { + 'form_input': form_input, + 'input_test': input_test + // Add more form input components here if needed +} + +module.exports = program + +async function program(opts) { + const { id, sdb } = await get(opts.sid) + const { drive } = sdb + + const on = { + style: inject, + variables: onvariables, + } + + let variables = [] + + const _ = { + send_quick_actions: null, + send_actions: null, + send_form_input: {}, + send_steps_wizard: null + } + + const el = document.createElement('div') + const shadow = el.attachShadow({ mode: 'closed' }) + shadow.innerHTML = ` +
+ + + + +
+ + ` + + const style = shadow.querySelector('style') + const steps_wizard_placeholder = shadow.querySelector('steps-wizard') + const quick_actions_placeholder = shadow.querySelector('quick-actions') + const actions_placeholder = shadow.querySelector('actions') + const form_input_placeholder = shadow.querySelector('form-input') + + const subs = await sdb.watch(onbatch) + + const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) + quick_actions_placeholder.replaceWith(quick_actions_el) + + const actions_el = await actions(subs[1], actions_protocol) + actions_el.classList.add('hide') + actions_placeholder.replaceWith(actions_el) + + const steps_wizard_el = await steps_wizard(subs[2], steps_wizard_protocol) + steps_wizard_el.classList.add('hide') + steps_wizard_placeholder.replaceWith(steps_wizard_el) + + const form_input_elements = {} + + for (const [component_name, component_fn] of Object.entries(component_modules)) { + const index = get_form_input_component_index(component_name) + const el = await component_fn(subs[index], form_input_protocol(component_name)) + el.classList.add('hide') + form_input_elements[component_name] = el + form_input_placeholder.parentNode.insertBefore(el, form_input_placeholder) + } + + form_input_placeholder.remove() + + return el + + // --- Internal Functions --- + async function onbatch(batch) { + for (const { type, paths } of batch) { + const data = await Promise.all(paths.map(path => drive.get(path).then(file => file.raw))) + const func = on[type] || fail + func(data, type) + } + } + + function fail(data, type) { + throw new Error('invalid message', { cause: { data, type } }) + } + + function inject(data) { + style.replaceChildren((() => { + return document.createElement('style').textContent = data[0] + })()) + } + + function onvariables(data) { + const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] + variables = vars['change_path'] + if (_.send_steps_wizard) + _.send_steps_wizard({ type: "init_data", data: variables }) + } + + function toggle_view(el, show) { + el.classList.toggle('hide', !show) + } + + function steps_toggle_view(display) { + toggle_view(steps_wizard_el, display === 'block') + } + + function actions_toggle_view(display) { + toggle_view(actions_el, display === 'block') + } + + function form_input_protocol(component_name) { + return function (send) { + _.send_form_input[component_name] = send + return function on({ type, data }) { + if (type === 'action_submitted') { + const step = variables[data?.index] + Object.assign(step, { + is_completed: true, + status: 'completed', + data: data?.value + }) + drive.put('variables/program.json', { change_path: variables }) + } + } + } + } + + function steps_wizard_protocol(send) { + _.send_steps_wizard = send + return on + function on({ type, data }) { + if (type === 'step_clicked') { + console.log('step clicked data---------', type, data) + _.send_quick_actions({ + type: 'update_steps', + data: { + current_step: data?.index + 1, + total_steps: data?.total_steps + } + }) + + render_form_component(data.component) + const send = _.send_form_input[data.component] + if (send) send({ type: 'step_data', data }) + } + } + } + + function render_form_component(component_name) { + for (const name in form_input_elements) { + toggle_view(form_input_elements[name], name === component_name) + } + } + + function get_form_input_component_index(component) { + const { _: components } = fallback_module() + return Object.keys(components).indexOf(component) + } + + function actions_protocol(send) { + _.send_actions = send + return on + function on({ type, data }) { + _.send_quick_actions({ + type, + data: { + ...data, + total_steps: variables.length + } + }) + _.send_steps_wizard({ type: 'init_data', data: variables }) + steps_toggle_view('block') + + // render_form_component(data.component) + // const send = _.send_form_input[data.component] + // if (send) send({ type: 'step_data', data }) + + actions_toggle_view('none') + } + } + + function quick_actions_protocol(send) { + _.send_quick_actions = send + return on + function on({ type, data }) { + on_quick_actions_message({ type, data }) + } + } + + function on_quick_actions_message({ type, data }) { + if (type == 'display_actions') { + actions_toggle_view(data) + if (data === 'none') { + steps_toggle_view(data) + for (const el of Object.values(form_input_elements)) { + toggle_view(el, false) + } + cleanup() + } + } else if (type == 'action_submitted') { + const is_completed = variables[data?.total_steps - 1]?.is_completed + if (is_completed) { + alert(JSON.stringify(variables.map(step => step.data), null, 2)) + _.send_quick_actions?.({ type: 'deactivate_input_field' }) + } + } + } + + function cleanup() { + const cleaned = variables.map(step => ({ + ...step, + is_completed: false, + data: '' + })) + drive.put('variables/program.json', { change_path: cleaned }) + } +} + +// --- Fallback Module --- +function fallback_module() { + return { + api: fallback_instance, + _: { + 'quick_actions': { $: '' }, + 'actions': { $: '' }, + 'steps_wizard': { $: '' }, + 'form_input': { $: '' }, + 'input_test': { $: '' } + } + } + + function fallback_instance() { + return { + _: { + 'quick_actions': { + 0: '', + mapping: { + 'style': 'style', + 'icons': 'icons', + 'actions': 'actions', + 'hardcons': 'hardcons' + } + }, + 'actions': { + 0: '', + mapping: { + 'style': 'style', + 'actions': 'actions', + 'icons': 'icons', + 'hardcons': 'hardcons' + } + }, + 'steps_wizard': { + 0: '', + mapping: { + 'style': 'style', + 'variables': 'variables' + } + }, + 'form_input': { + 0: '', + mapping: { + 'style': 'style' + } + }, + 'input_test': { + 0: '', + mapping: { + 'style': 'style' + } + } + }, + drive: { + 'style/': { + 'program.css': { '$ref': 'program.css' } + }, + 'variables/': { + 'program.json': { '$ref': 'program.json' } + } + } + } + } +} + +}).call(this)}).call(this,"/src/node_modules/program/program.js") +},{"STATE":1,"actions":3,"form_input":5,"input_test":7,"quick_actions":10,"steps_wizard":13}],10:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -1470,6 +2020,11 @@ async function quick_actions(opts, protocol) { function onmessage ({ type, data }) { if (type === 'selected_action') { select_action(data) + } else if (type === 'update_steps') { + current_step.textContent = data.current_step + selected_action.current_step = data.current_step + } else if (type === 'deactivate_input_field') { + deactivate_input_field() } } function activate_input_field() { @@ -1488,12 +2043,6 @@ async function quick_actions(opts, protocol) { if (selected_action) { console.log('Selected action submitted:', selected_action) _.up({ type: 'action_submitted', data: selected_action }) - const nextStep = ++selected_action.current_step - current_step.textContent = nextStep - - if (nextStep > selected_action.total_steps) { - deactivate_input_field() - } } } function oninput(e) { @@ -1523,7 +2072,7 @@ async function quick_actions(opts, protocol) { slash_prefix.style.display = 'inline' command_text.style.display = 'inline' command_text.textContent = `#${selected_action.action}` - current_step.textContent = selected_action.current_step + current_step.textContent = selected_action?.current_step || 1 total_steps.textContent = selected_action.total_steps step_display.style.display = 'inline-flex' @@ -1807,7 +2356,7 @@ function fallback_module() { } } }).call(this)}).call(this,"/src/node_modules/quick_actions/quick_actions.js") -},{"STATE":1}],8:[function(require,module,exports){ +},{"STATE":1}],11:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2089,7 +2638,7 @@ function fallback_module(){ } } }).call(this)}).call(this,"/src/node_modules/quick_editor.js") -},{"STATE":1}],9:[function(require,module,exports){ +},{"STATE":1}],12:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2420,38 +2969,35 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/space.js") -},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":5,"tabbed_editor":11}],10:[function(require,module,exports){ +},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":6,"tabbed_editor":14}],13:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const quick_actions = require('quick_actions') -const actions = require('actions') - module.exports = steps_wizard -async function steps_wizard (opts) { +async function steps_wizard (opts, protocol) { const { id, sdb } = await get(opts.sid) const {drive} = sdb const on = { - style: inject, - variables: onvariables, + style: inject } let variables = [] - let current_step = 1; - let _ = {send_quick_actions: null} + let _ = null + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
-
-
-
+
@@ -2459,20 +3005,25 @@ async function steps_wizard (opts) { const style = shadow.querySelector('style') const steps_entries = shadow.querySelector('.steps-slot') - const quick_actions_placeholder = shadow.querySelector('.quick-actions') - const actions_placeholder = shadow.querySelector('.actions') - + const subs = await sdb.watch(onbatch) - const quick_actions_el = await quick_actions(subs[0], quick_actions_protocol) - quick_actions_placeholder.replaceWith(quick_actions_el) - - const actions_el = await actions(subs[1], actions_protocol) - actions_el.classList.add('hide') - actions_placeholder.replaceWith(actions_el) + // for demo purpose + render_steps([ + {name: "Optional Step", "type": "optional", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {name: "Step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} + ]) return el + function onmessage ({ type, data }) { + console.log('steps_ data', type, data) + if (type === 'init_data') { + variables = data + render_steps(variables) + } + } + function render_steps(steps) { if (!steps) return; @@ -2480,55 +3031,42 @@ async function steps_wizard (opts) { steps_entries.innerHTML = ''; steps.forEach((step, index) => { - const btn = document.createElement('button'); - btn.className = 'step-button'; - btn.textContent = step.name + (step.type === 'optional' ? ' *' : ''); - btn.setAttribute('data-step', index + 1); + const btn = document.createElement('button') + btn.className = 'step-button' + btn.textContent = step.name + (step.type === 'optional' ? ' *' : '') + btn.setAttribute('data-step', index + 1) - const accessible = can_access(index, steps); + const accessible = can_access(index, steps) - let status = 'default'; - if (!accessible) status = 'disabled'; - else if (step.is_completed) status = 'completed'; - else if (step.status === 'error') status = 'error'; - else if (step.type === 'optional') status = 'optional'; + let status = 'default' + if (!accessible) status = 'disabled' + else if (step.is_completed) status = 'completed' + else if (step.status === 'error') status = 'error' + else if (step.type === 'optional') status = 'optional' - btn.classList.add(`step-${status}`); - btn.disabled = (status === 'disabled'); + btn.classList.add(`step-${status}`) + btn.disabled = (status === 'disabled') - if (accessible) { - current_step = index + 1; - } - - btn.onclick = () => { + btn.onclick = async () => { if (!btn.disabled) { - console.log('Clicked:', step); + console.log('Clicked:', step) + _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) } }; - steps_entries.appendChild(btn); + steps_entries.appendChild(btn) }); - - if (_.send_quick_actions) { - _.send_quick_actions({ - type: 'update_steps', - data: { - current_step: current_step, - total_steps: steps.length - } - }); - } } function can_access(index, steps) { for (let i = 0; i < index; i++) { if (!steps[i].is_completed && steps[i].type !== 'optional') { - return false; + return false } } - return true; + return true } async function onbatch(batch) { @@ -2544,137 +3082,29 @@ async function steps_wizard (opts) { return document.createElement('style').textContent = data[0] })()) } - - function onvariables (data) { - const vars = typeof data[0] === 'string' ? JSON.parse(data[0]) : data[0] - variables = vars['change_path'] - render_steps(variables); - } - - - function cleanup () { - const cleaned = variables.map(step => ({ - ...step, - is_completed: false - })); - - drive.put('variables/steps_wizard.json', { change_path: cleaned }); - } - // ---- Toggle Views ---- - function toggle_view(el, show) { - el.classList.toggle('hide', !show); - } - - function steps_toggle_view(display) { - toggle_view(steps_entries, display === 'block'); - } - - function actions_toggle_view(display) { - toggle_view(actions_el, display === 'block'); - } - - // ---- Protocols ---- - function actions_protocol (send) { - _.send_actions = send - return on - function on ({ type, data }) { - console.log('actions data', type, data) - _.send_quick_actions({ - type, - data: { - ...data, - current_step: current_step, - total_steps: variables.length - } - }) - - steps_toggle_view('block') - actions_toggle_view('hide') - } - } - - function quick_actions_protocol (send) { - _.send_quick_actions = send - return on - function on ({ type, data }) { - onmessage({type, data}) - } - } - - function onmessage ({ type, data }) { - if (type == 'display_actions') { - actions_toggle_view(data) - if (data === 'none') { - steps_toggle_view(data) - cleanup() - } - } else if (type == 'action_submitted') { - const step = variables[data.current_step - 1] - Object.assign(step, { - is_completed: true, - status: 'completed' - }) - drive.put('variables/steps_wizard.json', {change_path : variables}) - } - } - + } - - function fallback_module () { return { - api: fallback_instance, - _: { - 'quick_actions': { - $: '' - }, - 'actions': { - $: '' - }, - } + api: fallback_instance } function fallback_instance () { return { - _: { - 'quick_actions': { - 0: '', - mapping: { - 'style': 'style', - 'icons': 'icons', - 'actions': 'actions', - 'hardcons': 'hardcons' - } - }, - 'actions': { - 0: '', - mapping: { - 'style': 'style', - 'actions': 'actions', - 'icons': 'icons', - 'hardcons': 'hardcons' - } - }, - }, drive: { 'style/': { 'stepswizard.css': { '$ref': 'stepswizard.css' } - }, - 'variables/': { - 'steps_wizard.json': { - '$ref': 'steps_wizard.json' - } - }, + } } } } } }).call(this)}).call(this,"/src/node_modules/steps_wizard/steps_wizard.js") -},{"STATE":1,"actions":3,"quick_actions":7}],11:[function(require,module,exports){ +},{"STATE":1}],14:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3068,7 +3498,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/tabbed_editor/tabbed_editor.js") -},{"STATE":1}],12:[function(require,module,exports){ +},{"STATE":1}],15:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3280,7 +3710,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/tabs/tabs.js") -},{"STATE":1}],13:[function(require,module,exports){ +},{"STATE":1}],16:[function(require,module,exports){ (function (__filename){(function (){ const state = require('STATE') const state_db = state(__filename) @@ -3463,7 +3893,7 @@ function fallback_module () { } } }).call(this)}).call(this,"/src/node_modules/tabsbar/tabsbar.js") -},{"STATE":1,"tabs":12,"task_manager":14}],14:[function(require,module,exports){ +},{"STATE":1,"tabs":15,"task_manager":17}],17:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3556,7 +3986,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/task_manager.js") -},{"STATE":1}],15:[function(require,module,exports){ +},{"STATE":1}],18:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3714,7 +4144,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/taskbar/taskbar.js") -},{"STATE":1,"action_bar":2,"tabsbar":13}],16:[function(require,module,exports){ +},{"STATE":1,"action_bar":2,"tabsbar":16}],19:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3850,7 +4280,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/theme_widget/theme_widget.js") -},{"STATE":1,"space":9,"taskbar":15}],17:[function(require,module,exports){ +},{"STATE":1,"space":12,"taskbar":18}],20:[function(require,module,exports){ const prefix = 'https://raw.githubusercontent.com/alyhxn/playproject/main/' const init_url = location.hash === '#dev' ? 'web/init.js' : prefix + 'src/node_modules/init.js' const args = arguments @@ -3871,7 +4301,7 @@ fetch(init_url, fetch_opts).then(res => res.text()).then(async source => { require('./page') // or whatever is otherwise the main entry of our project }) -},{"./page":18}],18:[function(require,module,exports){ +},{"./page":21}],21:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('../src/node_modules/STATE') const statedb = STATE(__filename) @@ -3894,6 +4324,7 @@ const task_manager = require('../src/node_modules/task_manager') const quick_actions = require('../src/node_modules/quick_actions') const graph_explorer = require('../src/node_modules/graph_explorer') const editor = require('../src/node_modules/quick_editor') +const program = require('../src/node_modules/program') const steps_wizard = require('../src/node_modules/steps_wizard') const imports = { @@ -3909,6 +4340,7 @@ const imports = { task_manager, quick_actions, graph_explorer, + program, steps_wizard, } config().then(() => boot({ sid: '' })) @@ -4170,7 +4602,8 @@ function fallback_module () { '../src/node_modules/task_manager', '../src/node_modules/quick_actions', '../src/node_modules/graph_explorer', - '../src/node_modules/steps_wizard' + '../src/node_modules/program', + '../src/node_modules/steps_wizard', ] const subs = {} names.forEach(subgen) @@ -4184,7 +4617,7 @@ function fallback_module () { 'style': 'style' } } - subs['../src/node_modules/steps_wizard'] = { + subs['../src/node_modules/program'] = { $: '', 0: '', mapping: { @@ -4192,6 +4625,13 @@ function fallback_module () { 'style': 'style' } } + subs['../src/node_modules/steps_wizard'] = { + $: '', + 0: '', + mapping: { + 'style': 'style' + } + } subs['../src/node_modules/tabsbar'] = { $: '', 0: '', @@ -4414,4 +4854,4 @@ function fallback_module () { } }).call(this)}).call(this,"/web/page.js") -},{"../src/node_modules/STATE":1,"../src/node_modules/action_bar":2,"../src/node_modules/actions":3,"../src/node_modules/console_history":4,"../src/node_modules/graph_explorer":5,"../src/node_modules/menu":6,"../src/node_modules/quick_actions":7,"../src/node_modules/quick_editor":8,"../src/node_modules/space":9,"../src/node_modules/steps_wizard":10,"../src/node_modules/tabbed_editor":11,"../src/node_modules/tabs":12,"../src/node_modules/tabsbar":13,"../src/node_modules/task_manager":14,"../src/node_modules/taskbar":15,"../src/node_modules/theme_widget":16}]},{},[17]); +},{"../src/node_modules/STATE":1,"../src/node_modules/action_bar":2,"../src/node_modules/actions":3,"../src/node_modules/console_history":4,"../src/node_modules/graph_explorer":6,"../src/node_modules/menu":8,"../src/node_modules/program":9,"../src/node_modules/quick_actions":10,"../src/node_modules/quick_editor":11,"../src/node_modules/space":12,"../src/node_modules/steps_wizard":13,"../src/node_modules/tabbed_editor":14,"../src/node_modules/tabs":15,"../src/node_modules/tabsbar":16,"../src/node_modules/task_manager":17,"../src/node_modules/taskbar":18,"../src/node_modules/theme_widget":19}]},{},[20]); From 68ed17a855e1f102c891e233ffa658d67e3cb990 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 5 Jul 2025 19:39:04 +0500 Subject: [PATCH 16/21] remove comment --- src/node_modules/program/program.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/node_modules/program/program.js b/src/node_modules/program/program.js index 0f869ee..c8aeaef 100644 --- a/src/node_modules/program/program.js +++ b/src/node_modules/program/program.js @@ -139,7 +139,6 @@ async function program(opts) { return on function on({ type, data }) { if (type === 'step_clicked') { - console.log('step clicked data---------', type, data) _.send_quick_actions({ type: 'update_steps', data: { @@ -180,10 +179,6 @@ async function program(opts) { _.send_steps_wizard({ type: 'init_data', data: variables }) steps_toggle_view('block') - // render_form_component(data.component) - // const send = _.send_form_input[data.component] - // if (send) send({ type: 'step_data', data }) - actions_toggle_view('none') } } From 7ac2c485a353f19845e50ce2b25173db57df2a08 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Thu, 10 Jul 2025 21:52:06 +0500 Subject: [PATCH 17/21] add ui changes --- src/node_modules/program/program.js | 19 ++++++++++++------- .../quick_actions/quick_actions.js | 7 ++++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/node_modules/program/program.js b/src/node_modules/program/program.js index c8aeaef..e881b81 100644 --- a/src/node_modules/program/program.js +++ b/src/node_modules/program/program.js @@ -9,8 +9,8 @@ const steps_wizard = require('steps_wizard') const input_test = require('input_test') const component_modules = { - 'form_input': form_input, - 'input_test': input_test + form_input, + input_test // Add more form input components here if needed } @@ -129,6 +129,10 @@ async function program(opts) { data: data?.value }) drive.put('variables/program.json', { change_path: variables }) + + if (variables[variables.length - 1]?.is_completed) { + _.send_quick_actions({ type: 'show_submit_btn' }) + } } } } @@ -179,6 +183,10 @@ async function program(opts) { _.send_steps_wizard({ type: 'init_data', data: variables }) steps_toggle_view('block') + if (variables.length > 0) { + const firstStep = variables[0] + render_form_component(firstStep.component) + } actions_toggle_view('none') } } @@ -202,11 +210,8 @@ async function program(opts) { cleanup() } } else if (type == 'action_submitted') { - const is_completed = variables[data?.total_steps - 1]?.is_completed - if (is_completed) { - alert(JSON.stringify(variables.map(step => step.data), null, 2)) - _.send_quick_actions?.({ type: 'deactivate_input_field' }) - } + alert(JSON.stringify(variables.map(step => step.data), null, 2)) + _.send_quick_actions?.({ type: 'deactivate_input_field' }) } } diff --git a/src/node_modules/quick_actions/quick_actions.js b/src/node_modules/quick_actions/quick_actions.js index 88dfc24..7895827 100644 --- a/src/node_modules/quick_actions/quick_actions.js +++ b/src/node_modules/quick_actions/quick_actions.js @@ -85,6 +85,8 @@ async function quick_actions(opts, protocol) { selected_action.current_step = data.current_step } else if (type === 'deactivate_input_field') { deactivate_input_field() + } else if (type == 'show_submit_btn') { + show_submit_btn() } } function activate_input_field() { @@ -127,6 +129,10 @@ async function quick_actions(opts, protocol) { update_input_display(selected_action) } + function show_submit_btn() { + submit_btn.style.display = 'flex' + } + function update_input_display(selected_action = null) { if (selected_action) { slash_prefix.style.display = 'inline' @@ -137,7 +143,6 @@ async function quick_actions(opts, protocol) { step_display.style.display = 'inline-flex' input_field.style.display = 'none' - submit_btn.style.display = 'flex' } else { slash_prefix.style.display = 'none' command_text.style.display = 'none' From b86d1b44ece6f1d0c6c39c77901b904664954816 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 12 Jul 2025 21:44:12 +0500 Subject: [PATCH 18/21] add view any step form --- bundle.js | 74 ++++++++++++++----- src/node_modules/form_input.js | 19 +++++ src/node_modules/input_test.js | 15 +++- src/node_modules/program/program.js | 1 + src/node_modules/steps_wizard/steps_wizard.js | 8 +- src/node_modules/steps_wizard/stepswizard.css | 1 - 6 files changed, 94 insertions(+), 24 deletions(-) diff --git a/bundle.js b/bundle.js index 7ce0ab0..5dea087 100644 --- a/bundle.js +++ b/bundle.js @@ -832,6 +832,7 @@ async function form_input (opts, protocol) { } let current_step = null + let input_accessible = true if(protocol){ send = protocol(msg => onmessage(msg)) @@ -845,14 +846,17 @@ async function form_input (opts, protocol) {
+
` const style = shadow.querySelector('style') const input_field_el = shadow.querySelector('.input-field') + const overlay_el = shadow.querySelector('.overlay-lock') input_field_el.oninput = function () { + if (!input_accessible) return if (this.value.length >= 10) { _.up({ type: 'action_submitted', @@ -892,6 +896,13 @@ async function form_input (opts, protocol) { current_step = data console.log('message from form_input', input_field_el, input_field_el.value) input_field_el.value = data?.data || '' + input_accessible = data?.is_accessible !== false + + overlay_el.hidden = input_accessible + + input_field_el.placeholder = input_accessible + ? 'Type to submit' + : 'Input disabled for this step' } } @@ -907,6 +918,7 @@ function fallback_module () { 'theme.css': { raw: ` .input-display { + position: relative; background: #131315; border-radius: 16px; border: 1px solid #3c3c3c; @@ -933,6 +945,13 @@ function fallback_module () { .input-field::placeholder { color: #a6a6a6; } + .overlay-lock { + position: absolute; + inset: 0; + background: transparent; + z-index: 10; + cursor: not-allowed; + } ` } } @@ -1273,7 +1292,8 @@ async function input_test (opts, protocol) { } let current_step = null - + let input_accessible = true + if(protocol){ send = protocol(msg => onmessage(msg)) _ = { up: send } @@ -1285,14 +1305,17 @@ async function input_test (opts, protocol) {
Testing 2nd Type
+
` const style = shadow.querySelector('style') const input_field_el = shadow.querySelector('.input-field') + const overlay_el = shadow.querySelector('.overlay-lock') input_field_el.oninput = function () { + if (!input_accessible) return if (this.value.length >= 10) { _.up({ type: 'action_submitted', @@ -1331,6 +1354,14 @@ async function input_test (opts, protocol) { if (type === 'step_data') { current_step = data input_field_el.value = data?.data || '' + + input_accessible = data?.is_accessible !== false + + overlay_el.hidden = input_accessible + + input_field_el.placeholder = input_accessible + ? 'Type to submit' + : 'Input disabled for this step' } } @@ -1350,6 +1381,7 @@ function fallback_module () { font-size: 18px; } .input-display { + position: relative; background: #131315; border-radius: 16px; border: 1px solid #3c3c3c; @@ -1653,8 +1685,8 @@ const steps_wizard = require('steps_wizard') const input_test = require('input_test') const component_modules = { - 'form_input': form_input, - 'input_test': input_test + form_input, + input_test // Add more form input components here if needed } @@ -1773,6 +1805,10 @@ async function program(opts) { data: data?.value }) drive.put('variables/program.json', { change_path: variables }) + + if (variables[variables.length - 1]?.is_completed) { + _.send_quick_actions({ type: 'show_submit_btn' }) + } } } } @@ -1783,7 +1819,6 @@ async function program(opts) { return on function on({ type, data }) { if (type === 'step_clicked') { - console.log('step clicked data---------', type, data) _.send_quick_actions({ type: 'update_steps', data: { @@ -1794,6 +1829,7 @@ async function program(opts) { render_form_component(data.component) const send = _.send_form_input[data.component] + console.log('step_clicked_Data', data) if (send) send({ type: 'step_data', data }) } } @@ -1824,10 +1860,10 @@ async function program(opts) { _.send_steps_wizard({ type: 'init_data', data: variables }) steps_toggle_view('block') - // render_form_component(data.component) - // const send = _.send_form_input[data.component] - // if (send) send({ type: 'step_data', data }) - + if (variables.length > 0) { + const firstStep = variables[0] + render_form_component(firstStep.component) + } actions_toggle_view('none') } } @@ -1851,11 +1887,8 @@ async function program(opts) { cleanup() } } else if (type == 'action_submitted') { - const is_completed = variables[data?.total_steps - 1]?.is_completed - if (is_completed) { - alert(JSON.stringify(variables.map(step => step.data), null, 2)) - _.send_quick_actions?.({ type: 'deactivate_input_field' }) - } + alert(JSON.stringify(variables.map(step => step.data), null, 2)) + _.send_quick_actions?.({ type: 'deactivate_input_field' }) } } @@ -2025,6 +2058,8 @@ async function quick_actions(opts, protocol) { selected_action.current_step = data.current_step } else if (type === 'deactivate_input_field') { deactivate_input_field() + } else if (type == 'show_submit_btn') { + show_submit_btn() } } function activate_input_field() { @@ -2067,6 +2102,10 @@ async function quick_actions(opts, protocol) { update_input_display(selected_action) } + function show_submit_btn() { + submit_btn.style.display = 'flex' + } + function update_input_display(selected_action = null) { if (selected_action) { slash_prefix.style.display = 'inline' @@ -2077,7 +2116,6 @@ async function quick_actions(opts, protocol) { step_display.style.display = 'inline-flex' input_field.style.display = 'none' - submit_btn.style.display = 'flex' } else { slash_prefix.style.display = 'none' command_text.style.display = 'none' @@ -3045,13 +3083,13 @@ async function steps_wizard (opts, protocol) { else if (step.type === 'optional') status = 'optional' btn.classList.add(`step-${status}`) - btn.disabled = (status === 'disabled') + // btn.disabled = (status === 'disabled') btn.onclick = async () => { - if (!btn.disabled) { + // if (!btn.disabled) { console.log('Clicked:', step) - _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) - } + _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length, is_accessible: accessible}}) + }; steps_entries.appendChild(btn) diff --git a/src/node_modules/form_input.js b/src/node_modules/form_input.js index 6c463d6..8b53b51 100644 --- a/src/node_modules/form_input.js +++ b/src/node_modules/form_input.js @@ -12,6 +12,7 @@ async function form_input (opts, protocol) { } let current_step = null + let input_accessible = true if(protocol){ send = protocol(msg => onmessage(msg)) @@ -25,14 +26,17 @@ async function form_input (opts, protocol) {
+
` const style = shadow.querySelector('style') const input_field_el = shadow.querySelector('.input-field') + const overlay_el = shadow.querySelector('.overlay-lock') input_field_el.oninput = function () { + if (!input_accessible) return if (this.value.length >= 10) { _.up({ type: 'action_submitted', @@ -72,6 +76,13 @@ async function form_input (opts, protocol) { current_step = data console.log('message from form_input', input_field_el, input_field_el.value) input_field_el.value = data?.data || '' + input_accessible = data?.is_accessible !== false + + overlay_el.hidden = input_accessible + + input_field_el.placeholder = input_accessible + ? 'Type to submit' + : 'Input disabled for this step' } } @@ -87,6 +98,7 @@ function fallback_module () { 'theme.css': { raw: ` .input-display { + position: relative; background: #131315; border-radius: 16px; border: 1px solid #3c3c3c; @@ -113,6 +125,13 @@ function fallback_module () { .input-field::placeholder { color: #a6a6a6; } + .overlay-lock { + position: absolute; + inset: 0; + background: transparent; + z-index: 10; + cursor: not-allowed; + } ` } } diff --git a/src/node_modules/input_test.js b/src/node_modules/input_test.js index 2b0bd2a..73c2cd1 100644 --- a/src/node_modules/input_test.js +++ b/src/node_modules/input_test.js @@ -12,7 +12,8 @@ async function input_test (opts, protocol) { } let current_step = null - + let input_accessible = true + if(protocol){ send = protocol(msg => onmessage(msg)) _ = { up: send } @@ -24,14 +25,17 @@ async function input_test (opts, protocol) {
Testing 2nd Type
+
` const style = shadow.querySelector('style') const input_field_el = shadow.querySelector('.input-field') + const overlay_el = shadow.querySelector('.overlay-lock') input_field_el.oninput = function () { + if (!input_accessible) return if (this.value.length >= 10) { _.up({ type: 'action_submitted', @@ -70,6 +74,14 @@ async function input_test (opts, protocol) { if (type === 'step_data') { current_step = data input_field_el.value = data?.data || '' + + input_accessible = data?.is_accessible !== false + + overlay_el.hidden = input_accessible + + input_field_el.placeholder = input_accessible + ? 'Type to submit' + : 'Input disabled for this step' } } @@ -89,6 +101,7 @@ function fallback_module () { font-size: 18px; } .input-display { + position: relative; background: #131315; border-radius: 16px; border: 1px solid #3c3c3c; diff --git a/src/node_modules/program/program.js b/src/node_modules/program/program.js index e881b81..a36dcee 100644 --- a/src/node_modules/program/program.js +++ b/src/node_modules/program/program.js @@ -153,6 +153,7 @@ async function program(opts) { render_form_component(data.component) const send = _.send_form_input[data.component] + console.log('step_clicked_Data', data) if (send) send({ type: 'step_data', data }) } } diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 798efcc..8fcc353 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -72,13 +72,13 @@ async function steps_wizard (opts, protocol) { else if (step.type === 'optional') status = 'optional' btn.classList.add(`step-${status}`) - btn.disabled = (status === 'disabled') + // btn.disabled = (status === 'disabled') btn.onclick = async () => { - if (!btn.disabled) { + // if (!btn.disabled) { console.log('Clicked:', step) - _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length}}) - } + _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length, is_accessible: accessible}}) + }; steps_entries.appendChild(btn) diff --git a/src/node_modules/steps_wizard/stepswizard.css b/src/node_modules/steps_wizard/stepswizard.css index 9f7a23c..a2da4a8 100644 --- a/src/node_modules/steps_wizard/stepswizard.css +++ b/src/node_modules/steps_wizard/stepswizard.css @@ -97,7 +97,6 @@ background-color: #444; border-color: #444; color: #ccc; - cursor: not-allowed; } .step-disabled:before { background-color: #444; From bc1a44b5268d75fdac9b4b6ccc53a700121fb43b Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sat, 12 Jul 2025 21:47:33 +0500 Subject: [PATCH 19/21] update bundle js --- bundle.js | 603 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 386 insertions(+), 217 deletions(-) diff --git a/bundle.js b/bundle.js index 80d47e8..2752a1e 100644 --- a/bundle.js +++ b/bundle.js @@ -175,7 +175,7 @@ function fallback_module() { } } }).call(this)}).call(this,"/src/node_modules/action_bar/action_bar.js") -},{"STATE":1,"quick_actions":7}],3:[function(require,module,exports){ +},{"STATE":1,"quick_actions":10}],3:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -820,7 +820,7 @@ function fallback_module () { (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) -const { get } = statedb(fallback_module) +const { sdb, get } = statedb(fallback_module) module.exports = form_input async function form_input (opts, protocol) { @@ -965,11 +965,11 @@ function fallback_module () { (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) -const { sdb, get } = statedb(fallback_module) +const { get } = statedb(fallback_module) -module.exports = component +module.exports = graph_explorer -async function component (opts, protocol) { +async function graph_explorer(opts) { const { sdb } = await get(opts.sid) const { drive } = sdb @@ -1041,123 +1041,279 @@ async function component (opts, protocol) { sheet.replaceSync(data[0]) shadow.adoptedStyleSheets = [sheet] } - /****************************************************************************** - Function for the rendering based on the visible nodes. - ******************************************************************************/ - function render_visible_nodes() { + + function build_and_render_view(focal_instance_path = null) { + const old_view = [...view] + const old_scroll_top = vertical_scroll_value + const old_scroll_left = horizontal_scroll_value + + view = build_view_recursive({ + base_path: '/', + parent_instance_path: '', + depth: 0, + is_last_sub : true, + is_hub: false, + parent_pipe_trail: [], + instance_states, + all_entries + }) + + let focal_index = -1 + if (focal_instance_path) { + focal_index = view.findIndex( + node => node.instance_path === focal_instance_path + ) + } + if (focal_index === -1) { + focal_index = Math.floor(old_scroll_top / node_height) + } + + const old_focal_node = old_view[focal_index] + let new_scroll_top = old_scroll_top + + if (old_focal_node) { + const old_focal_instance_path = old_focal_node.instance_path + const new_focal_index = view.findIndex( + node => node.instance_path === old_focal_instance_path + ) + if (new_focal_index !== -1) { + const scroll_diff = (new_focal_index - focal_index) * node_height + new_scroll_top = old_scroll_top + scroll_diff + } + } + + start_index = Math.max(0, focal_index - Math.floor(chunk_size / 2)) + end_index = start_index + container.replaceChildren() - if (entries.length === 0) return - - const visible_entries = calculate_visible_entries() - visible_entries.forEach(entry => { - const node = create_node(entry) - // console.log(container, node) - container.appendChild(node) - observer.observe(node) + container.appendChild(top_sentinel) + container.appendChild(bottom_sentinel) + observer.observe(top_sentinel) + observer.observe(bottom_sentinel) + + render_next_chunk() + + requestAnimationFrame(() => { + el.scrollTop = new_scroll_top + el.scrollLeft = old_scroll_left }) } - function calculate_visible_entries() { - const visible_entries = [] - visible_entries.push(entries[0]) - let queue = [...entries[0].subs.map(index => entries[index])] - - while (queue.length > 0 && visible_entries.length < view_num) { - const entry = queue.shift() - if (!entry) continue - visible_entries.push(entry) - - const entry_path = get_full_path(entry) - if (expanded_nodes.has(entry_path) && entry.subs && entry.subs.length > 0) { - queue = [...entry.subs.map(index => entries[index]), ...queue] + function build_view_recursive({ + base_path, + parent_instance_path, + depth, + is_last_sub, + is_hub, + parent_pipe_trail, + instance_states, + all_entries + }) { + + const instance_path = `${parent_instance_path}|${base_path}` + const entry = all_entries[base_path] + if (!entry) return [] + + if (!instance_states[instance_path]) { + instance_states[instance_path] = { + expanded_subs: false, + expanded_hubs: false } } - - return visible_entries - } - /****************************************************************************** - Create a node element for the explorer tree. - ******************************************************************************/ - function create_node(entry) { - const node = document.createElement('div') - const depth = calculate_depth(entry.path) - const is_expanded = expanded_nodes.has(get_full_path(entry)) - const has_children = entry.subs && entry.subs.length > 0 - - let icon = get_icon_for_type(entry.type) - let prefix = create_tree_prefix(entry, depth, is_expanded, has_children) - - node.className = 'explorer-node' - node.dataset.path = get_full_path(entry) - node.dataset.index = entries.indexOf(entry) - node.style.paddingLeft = `${depth * 10}px` - - node.innerHTML = ` - ${prefix} - ${icon} - ${entry.name} - ` - - // Setup click handlers - const prefix_el = node.querySelector('.tree-prefix') - const icon_el = node.querySelector('.node-icon') - - if (has_children) { - prefix_el.onclick = null - //TODO: Add supernode support - icon_el.onclick = () => toggle_node(entry) + const state = instance_states[instance_path] + const children_pipe_trail = [...parent_pipe_trail] + let last_pipe = null + + if (depth > 0) { + if (is_hub) { + last_pipe = [...parent_pipe_trail] + if (is_last_sub) { + children_pipe_trail.pop() + children_pipe_trail.push(is_last_sub) + last_pipe.pop() + last_pipe.push(true) + } + } + children_pipe_trail.push(!is_last_sub || is_hub) + } + + let current_view = [] + + if (state.expanded_hubs && entry.hubs) { + entry.hubs.forEach((hub_path, i, arr) => { + current_view = current_view.concat( + build_view_recursive({ + base_path: hub_path, + parent_instance_path: instance_path, + depth: depth + 1, + is_last_sub : i === arr.length - 1, + is_hub: true, + parent_pipe_trail: children_pipe_trail, + instance_states, + all_entries + }) + ) + }) } - - return node + + current_view.push({ + base_path, + instance_path, + depth, + is_last_sub, + is_hub, + pipe_trail: (is_hub && is_last_sub) ? last_pipe : parent_pipe_trail + }) + + if (state.expanded_subs && entry.subs) { + entry.subs.forEach((sub_path, i, arr) => { + current_view = current_view.concat( + build_view_recursive({ + base_path: sub_path, + parent_instance_path: instance_path, + depth: depth + 1, + is_last_sub: i === arr.length - 1, + is_hub: false, + parent_pipe_trail: children_pipe_trail, + instance_states, + all_entries + }) + ) + }) + } + return current_view } - // Toggle node expansion state - function toggle_node(entry) { - const path = get_full_path(entry) - - if (expanded_nodes.has(path)) { - expanded_nodes.delete(path) + function handle_sentinel_intersection(entries) { + entries.forEach(entry => { + if (entry.isIntersecting) { + if (entry.target === top_sentinel) render_prev_chunk() + else if (entry.target === bottom_sentinel) render_next_chunk() + } + }) + } + + function render_next_chunk() { + if (end_index >= view.length) return + const fragment = document.createDocumentFragment() + const next_end = Math.min(view.length, end_index + chunk_size) + for (let i = end_index; i < next_end; i++) { + fragment.appendChild(create_node(view[i])) + } + container.insertBefore(fragment, bottom_sentinel) + end_index = next_end + cleanup_dom(false) + } + + function render_prev_chunk() { + if (start_index <= 0) return + const fragment = document.createDocumentFragment() + const prev_start = Math.max(0, start_index - chunk_size) + for (let i = prev_start; i < start_index; i++) { + fragment.appendChild(create_node(view[i])) + } + const old_scroll_height = container.scrollHeight + const old_scroll_top = el.scrollTop + container.insertBefore(fragment, top_sentinel.nextSibling) + start_index = prev_start + el.scrollTop = old_scroll_top + (container.scrollHeight - old_scroll_height) + cleanup_dom(true) + } + + function cleanup_dom(is_scrolling_up) { + const rendered_count = end_index - start_index + if (rendered_count < max_rendered_nodes) return + const to_remove_count = rendered_count - max_rendered_nodes + if (is_scrolling_up) { + for (let i = 0; i < to_remove_count; i++) { + bottom_sentinel.previousElementSibling.remove() + } + end_index -= to_remove_count } else { - expanded_nodes.add(path) + for (let i = 0; i < to_remove_count; i++) { + top_sentinel.nextElementSibling.remove() + } + start_index += to_remove_count } - render_visible_nodes() - // console.log('view:', view) - // console.log('view:', view_num) } - // Get appropriate icon for entry type - function get_icon_for_type(type) { - const type_icons = { - 'root': '๐ŸŒ', - 'folder': '๐Ÿ“', - 'file': '๐Ÿ“„', - 'html-file': '๐Ÿ“„', - 'js-file': '๐Ÿ“„', - 'css-file': '๐Ÿ–Œ๏ธ', - 'json-file': '๐ŸŽจ' + function get_prefix(is_last_sub, has_subs, state, is_hub) { + const { expanded_subs, expanded_hubs } = state + if (is_hub) { + if (expanded_subs && expanded_hubs) return 'โ”Œโ”ผ' + if (expanded_subs) return 'โ”Œโ”ฌ' + if (expanded_hubs) return 'โ”Œโ”ด' + return 'โ”Œโ”€' + } else if (is_last_sub) { + if (expanded_subs && expanded_hubs) return 'โ””โ”ผ' + if (expanded_subs) return 'โ””โ”ฌ' + if (expanded_hubs) return 'โ””โ”ด' + return 'โ””โ”€' + } else { + if (expanded_subs && expanded_hubs) return 'โ”œโ”ผ' + if (expanded_subs) return 'โ”œโ”ฌ' + if (expanded_hubs) return 'โ”œโ”ด' + return 'โ”œโ”€' } + } + + function create_node({ base_path, instance_path, depth, is_last_sub, is_hub, pipe_trail }) { + const entry = all_entries[base_path] + const state = instance_states[instance_path] + const el = document.createElement('div') + el.className = `node type-${entry.type}` + el.dataset.instance_path = instance_path + + const has_hubs = entry.hubs && entry.hubs.length > 0 + const has_subs = entry.subs && entry.subs.length > 0 - return type_icons[type] || '๐Ÿ“„' - } - /****************************************************************************** - Prefix creation for tree structure. - //TODO: Add support for different icons based on entry type. - /******************************************************************************/ - function create_tree_prefix(entry, depth, is_expanded, has_children) { - if (depth === 0) return has_children ? (is_expanded ? '๐Ÿช„โ”ฌ' : '๐Ÿช„โ”ฌ') : '๐Ÿช„โ”€' - if (has_children) { - return is_expanded ? 'โ”œโ”ฌ' : 'โ”œโ”€' - } else { - return 'โ””โ”€' + if (depth) { + el.style.paddingLeft = '20px' + } + + if (base_path === '/' && instance_path === '|/') { + const { expanded_subs } = state + const prefix_symbol = expanded_subs ? '๐Ÿช„โ”ฌ' : '๐Ÿช„โ”€' + const prefix_class = has_subs ? 'prefix clickable' : 'prefix' + el.innerHTML = `${prefix_symbol}/๐ŸŒ` + if (has_subs) { + el.querySelector('.prefix').onclick = () => toggle_subs(instance_path) + el.querySelector('.name').onclick = () => toggle_subs(instance_path) + } + return el } + + const prefix_symbol = get_prefix(is_last_sub, has_subs, state, is_hub) + const pipe_html = pipe_trail.map(should_pipe => `${should_pipe ? 'โ”‚' : ' '}`).join('') + + const prefix_class = (!has_hubs || base_path !== '/') ? 'prefix clickable' : 'prefix' + const icon_class = has_subs ? 'icon clickable' : 'icon' + + el.innerHTML = ` + ${pipe_html} + ${prefix_symbol} + + ${entry.name} + ` + if(has_hubs && base_path !== '/') el.querySelector('.prefix').onclick = () => toggle_hubs(instance_path) + if(has_subs) el.querySelector('.icon').onclick = () => toggle_subs(instance_path) + return el } - function calculate_depth(path) { - if (!path) return 0 - return (path.match(/\//g) || []).length + function toggle_subs(instance_path) { + const state = instance_states[instance_path] + if (state) { + state.expanded_subs = !state.expanded_subs + build_and_render_view(instance_path) + } } - function get_full_path(entry) { - return entry.path + entry.name + '/' + + function toggle_hubs(instance_path) { + const state = instance_states[instance_path] + if (state) { + state.expanded_hubs = !state.expanded_hubs + build_and_render_view(instance_path) + } } } @@ -1165,74 +1321,57 @@ function fallback_module() { return { api: fallback_instance } - function fallback_instance() { return { drive: { + 'entries/': { + 'entries.json': { $ref: 'entries.json' } + }, 'style/': { 'theme.css': { raw: ` - .graph-explorer { - height: 300px; - overflow: auto; - font-family: monospace; - color: #eee; - background-color: #2d3440; - user-select: none; - } - - .explorer-container { + .graph-container { + color: #abb2bf; + background-color: #282c34; padding: 10px; - height: 300px; + height: 500px; /* Or make it flexible */ + overflow: auto; } - - .explorer-node { + .node { display: flex; align-items: center; - padding: 2px 0; white-space: nowrap; - cursor: pointer; + cursor: default; + height: 22px; /* Important for scroll calculation */ } - - .explorer-node:hover { - background-color: rgba(255, 255, 255, 0.1); + .indent { + display: flex; } - - .tree-prefix { - margin-right: 4px; - opacity: 0.7; - cursor: pointer; + .pipe { + text-align: center; } - - .node-icon { - margin-right: 6px; + .blank { + width: 10px; + text-align: center; + } + .clickable { cursor: pointer; } - - .node-name { - overflow: hidden; - text-overflow: ellipsis; + .prefix, .icon { + margin-right: 6px; } + .icon { display: inline-block; text-align: center; } + .name { flex-grow: 1; } + .node.type-root > .icon::before { content: '๐ŸŒ'; } + .node.type-folder > .icon::before { content: '๐Ÿ“'; } + .node.type-html-file > .icon::before { content: '๐Ÿ“„'; } + .node.type-js-file > .icon::before { content: '๐Ÿ“œ'; } + .node.type-css-file > .icon::before { content: '๐ŸŽจ'; } + .node.type-json-file > .icon::before { content: '๐Ÿ“'; } + .node.type-file > .icon::before { content: '๐Ÿ“„'; } + .sentinel { height: 1px; } ` } - }, - 'entries/': { - 'graph.json': { - '$ref': 'entries.json' - } - }, - 'icons/': { - 'folder_icons.json': { - raw: `{ - "root": "๐ŸŒ", - "folder": "๐Ÿ“", - "file": "๐Ÿ“„", - "html-file": "๐Ÿ“„", - "js-file": "๐Ÿ“„", - "css-file": "๐Ÿ–Œ๏ธ", - "json-file": "๐ŸŽจ" - }` - } } } } @@ -1328,18 +1467,15 @@ async function input_test (opts, protocol) { : 'Input disabled for this step' } } -} -function fallback_module() { +} +function fallback_module () { return { - api: fallback_instance + api: fallback_instance, } - function fallback_instance() { + function fallback_instance () { return { drive: { - 'entries/': { - 'entries.json': { $ref: 'entries.json' } - }, 'style/': { 'theme.css': { raw: ` @@ -1383,8 +1519,8 @@ function fallback_module() { } } -}).call(this)}).call(this,"/src/node_modules/graph_explorer/graph_explorer.js") -},{"STATE":1}],6:[function(require,module,exports){ +}).call(this)}).call(this,"/src/node_modules/input_test.js") +},{"STATE":1}],8:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -1966,6 +2102,12 @@ async function quick_actions(opts, protocol) {
/ +
@@ -1982,6 +2124,9 @@ async function quick_actions(opts, protocol) { const input_field = shadow.querySelector('.input-field') const submit_btn = shadow.querySelector('.submit-btn') const close_btn = shadow.querySelector('.close-btn') + const step_display = shadow.querySelector('.step-display') + const current_step = shadow.querySelector('.current-step') + const total_steps = shadow.querySelector('.total-step') const style = shadow.querySelector('style') const main = shadow.querySelector('.main') @@ -2068,13 +2213,18 @@ async function quick_actions(opts, protocol) { if (selected_action) { slash_prefix.style.display = 'inline' command_text.style.display = 'inline' - command_text.textContent = `"${selected_action.action}"` + command_text.textContent = `#${selected_action.action}` + current_step.textContent = selected_action?.current_step || 1 + total_steps.textContent = selected_action.total_steps + step_display.style.display = 'inline-flex' + input_field.style.display = 'none' } else { slash_prefix.style.display = 'none' command_text.style.display = 'none' input_field.style.display = 'block' submit_btn.style.display = 'none' + step_display.style.display = 'none' input_field.placeholder = 'Type to search actions...' } } @@ -2317,6 +2467,28 @@ function fallback_module() { width: 16px; height: 16px; } + .step-display { + display: inline-flex; + align-items: center; + gap: 2px; + margin-left: 8px; + background: #2d2d2d; + border: 1px solid #666; + border-radius: 4px; + padding: 1px 6px; + font-size: 12px; + color: #fff; + font-family: monospace; + } + .current-step { + color:#f0f0f0; + } + .step-separator { + color: #888; + } + .total-step { + color: #f0f0f0; + } ` } } @@ -2325,7 +2497,7 @@ function fallback_module() { } } }).call(this)}).call(this,"/src/node_modules/quick_actions/quick_actions.js") -},{"STATE":1}],8:[function(require,module,exports){ +},{"STATE":1}],11:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2607,7 +2779,7 @@ function fallback_module(){ } } }).call(this)}).call(this,"/src/node_modules/quick_editor.js") -},{"STATE":1}],9:[function(require,module,exports){ +},{"STATE":1}],12:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -2937,46 +3109,51 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/space.js") -},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":5,"tabbed_editor":11}],10:[function(require,module,exports){ +},{"STATE":1,"actions":3,"console_history":4,"graph_explorer":6,"tabbed_editor":14}],13:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) const { sdb, get } = statedb(fallback_module) -const actions = require('actions') - - module.exports = steps_wizard -async function steps_wizard (opts) { +async function steps_wizard (opts, protocol) { const { id, sdb } = await get(opts.sid) const {drive} = sdb + const on = { style: inject } + let variables = [] + + let _ = null + if(protocol){ + send = protocol(msg => onmessage(msg)) + _ = { up: send } + } + const el = document.createElement('div') const shadow = el.attachShadow({ mode: 'closed' }) shadow.innerHTML = `
-
+
` const style = shadow.querySelector('style') - const main = shadow.querySelector('.main') - const actions_slot = shadow.querySelector('.actions-slot') - - + const steps_entries = shadow.querySelector('.steps-slot') + const subs = await sdb.watch(onbatch) - let actions_el = null + // for demo purpose + render_steps([ + {name: "Optional Step", "type": "optional", "is_completed": false, "component": "form_input", "status": "default", "data": ""}, + {name: "Step 2", "type": "mandatory", "is_completed": false, "component": "form_input", "status": "default", "data": ""} + ]) - actions_el = await actions(subs[0]) - actions_slot.replaceWith(actions_el) - return el function onmessage ({ type, data }) { @@ -3045,46 +3222,20 @@ async function steps_wizard (opts) { return document.createElement('style').textContent = data[0] })()) } + } function fallback_module () { return { - api: fallback_instance, - _: { - 'actions': { - $: '' - }, - } + api: fallback_instance } function fallback_instance () { return { - _: { - 'actions': { - 0: '', - mapping: { - 'style': 'style', - 'actions': 'actions', - 'icons': 'icons', - 'hardcons': 'hardcons' - } - } - }, drive: { 'style/': { 'stepswizard.css': { - raw: ` - .steps-wizard { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - background: #131315; - } - .space{ - height: inherit; - } - ` + '$ref': 'stepswizard.css' } } } @@ -3093,7 +3244,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/steps_wizard/steps_wizard.js") -},{"STATE":1,"actions":3}],11:[function(require,module,exports){ +},{"STATE":1}],14:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3487,7 +3638,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/tabbed_editor/tabbed_editor.js") -},{"STATE":1}],12:[function(require,module,exports){ +},{"STATE":1}],15:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3699,7 +3850,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/tabs/tabs.js") -},{"STATE":1}],13:[function(require,module,exports){ +},{"STATE":1}],16:[function(require,module,exports){ (function (__filename){(function (){ const state = require('STATE') const state_db = state(__filename) @@ -3882,7 +4033,7 @@ function fallback_module () { } } }).call(this)}).call(this,"/src/node_modules/tabsbar/tabsbar.js") -},{"STATE":1,"tabs":12,"task_manager":14}],14:[function(require,module,exports){ +},{"STATE":1,"tabs":15,"task_manager":17}],17:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -3975,7 +4126,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/task_manager.js") -},{"STATE":1}],15:[function(require,module,exports){ +},{"STATE":1}],18:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -4133,7 +4284,7 @@ function fallback_module() { } }).call(this)}).call(this,"/src/node_modules/taskbar/taskbar.js") -},{"STATE":1,"action_bar":2,"tabsbar":13}],16:[function(require,module,exports){ +},{"STATE":1,"action_bar":2,"tabsbar":16}],19:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('STATE') const statedb = STATE(__filename) @@ -4269,7 +4420,7 @@ function fallback_module () { } }).call(this)}).call(this,"/src/node_modules/theme_widget/theme_widget.js") -},{"STATE":1,"space":9,"taskbar":15}],17:[function(require,module,exports){ +},{"STATE":1,"space":12,"taskbar":18}],20:[function(require,module,exports){ const prefix = 'https://raw.githubusercontent.com/alyhxn/playproject/main/' const init_url = location.hash === '#dev' ? 'web/init.js' : prefix + 'src/node_modules/init.js' const args = arguments @@ -4290,7 +4441,7 @@ fetch(init_url, fetch_opts).then(res => res.text()).then(async source => { require('./page') // or whatever is otherwise the main entry of our project }) -},{"./page":18}],18:[function(require,module,exports){ +},{"./page":21}],21:[function(require,module,exports){ (function (__filename){(function (){ const STATE = require('../src/node_modules/STATE') const statedb = STATE(__filename) @@ -4313,6 +4464,7 @@ const task_manager = require('../src/node_modules/task_manager') const quick_actions = require('../src/node_modules/quick_actions') const graph_explorer = require('../src/node_modules/graph_explorer') const editor = require('../src/node_modules/quick_editor') +const program = require('../src/node_modules/program') const steps_wizard = require('../src/node_modules/steps_wizard') const imports = { @@ -4328,6 +4480,7 @@ const imports = { task_manager, quick_actions, graph_explorer, + program, steps_wizard, } config().then(() => boot({ sid: '' })) @@ -4589,7 +4742,8 @@ function fallback_module () { '../src/node_modules/task_manager', '../src/node_modules/quick_actions', '../src/node_modules/graph_explorer', - '../src/node_modules/steps_wizard' + '../src/node_modules/program', + '../src/node_modules/steps_wizard', ] const subs = {} names.forEach(subgen) @@ -4603,6 +4757,21 @@ function fallback_module () { 'style': 'style' } } + subs['../src/node_modules/program'] = { + $: '', + 0: '', + mapping: { + 'variables': 'variables', + 'style': 'style' + } + } + subs['../src/node_modules/steps_wizard'] = { + $: '', + 0: '', + mapping: { + 'style': 'style' + } + } subs['../src/node_modules/tabsbar'] = { $: '', 0: '', @@ -4823,4 +4992,4 @@ function fallback_module () { } }).call(this)}).call(this,"/web/page.js") -},{"../src/node_modules/STATE":1,"../src/node_modules/action_bar":2,"../src/node_modules/actions":3,"../src/node_modules/console_history":4,"../src/node_modules/graph_explorer":5,"../src/node_modules/menu":6,"../src/node_modules/quick_actions":7,"../src/node_modules/quick_editor":8,"../src/node_modules/space":9,"../src/node_modules/steps_wizard":10,"../src/node_modules/tabbed_editor":11,"../src/node_modules/tabs":12,"../src/node_modules/tabsbar":13,"../src/node_modules/task_manager":14,"../src/node_modules/taskbar":15,"../src/node_modules/theme_widget":16}]},{},[17]); \ No newline at end of file +},{"../src/node_modules/STATE":1,"../src/node_modules/action_bar":2,"../src/node_modules/actions":3,"../src/node_modules/console_history":4,"../src/node_modules/graph_explorer":6,"../src/node_modules/menu":8,"../src/node_modules/program":9,"../src/node_modules/quick_actions":10,"../src/node_modules/quick_editor":11,"../src/node_modules/space":12,"../src/node_modules/steps_wizard":13,"../src/node_modules/tabbed_editor":14,"../src/node_modules/tabs":15,"../src/node_modules/tabsbar":16,"../src/node_modules/task_manager":17,"../src/node_modules/taskbar":18,"../src/node_modules/theme_widget":19}]},{},[20]); From 175192795d9899dc3933e4d4819258171d6d6feb Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sun, 13 Jul 2025 00:07:09 +0500 Subject: [PATCH 20/21] add overlay lock --- src/node_modules/input_test.js | 7 +++++++ src/node_modules/steps_wizard/steps_wizard.js | 7 ++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/node_modules/input_test.js b/src/node_modules/input_test.js index 73c2cd1..66cba25 100644 --- a/src/node_modules/input_test.js +++ b/src/node_modules/input_test.js @@ -128,6 +128,13 @@ function fallback_module () { .input-field::placeholder { color: #a6a6a6; } + .overlay-lock { + position: absolute; + inset: 0; + background: transparent; + z-index: 10; + cursor: not-allowed; + } ` } } diff --git a/src/node_modules/steps_wizard/steps_wizard.js b/src/node_modules/steps_wizard/steps_wizard.js index 8fcc353..1dfadcf 100644 --- a/src/node_modules/steps_wizard/steps_wizard.js +++ b/src/node_modules/steps_wizard/steps_wizard.js @@ -72,13 +72,10 @@ async function steps_wizard (opts, protocol) { else if (step.type === 'optional') status = 'optional' btn.classList.add(`step-${status}`) - // btn.disabled = (status === 'disabled') btn.onclick = async () => { - // if (!btn.disabled) { - console.log('Clicked:', step) - _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length, is_accessible: accessible}}) - + console.log('Clicked:', step) + _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length, is_accessible: accessible}}) }; steps_entries.appendChild(btn) From 633eec8adbced19cc261293f802c943a59c0b088 Mon Sep 17 00:00:00 2001 From: Muhammad Azim Date: Sun, 13 Jul 2025 00:07:51 +0500 Subject: [PATCH 21/21] add overlay css --- bundle.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bundle.js b/bundle.js index 2752a1e..962d623 100644 --- a/bundle.js +++ b/bundle.js @@ -1511,6 +1511,13 @@ function fallback_module () { .input-field::placeholder { color: #a6a6a6; } + .overlay-lock { + position: absolute; + inset: 0; + background: transparent; + z-index: 10; + cursor: not-allowed; + } ` } } @@ -3185,13 +3192,10 @@ async function steps_wizard (opts, protocol) { else if (step.type === 'optional') status = 'optional' btn.classList.add(`step-${status}`) - // btn.disabled = (status === 'disabled') btn.onclick = async () => { - // if (!btn.disabled) { - console.log('Clicked:', step) - _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length, is_accessible: accessible}}) - + console.log('Clicked:', step) + _?.up({type: 'step_clicked', data: {...step, index, total_steps: steps.length, is_accessible: accessible}}) }; steps_entries.appendChild(btn)