change ui for entrypoint

This commit is contained in:
Dmitry Vasilev
2023-07-02 19:21:20 +03:00
parent 571db0bf41
commit b8c927c196
7 changed files with 94 additions and 113 deletions

View File

@@ -197,6 +197,9 @@ in production, you can do it like this:
Leporello.js appends `?leporello` query parameter to your HTML file, so you can Leporello.js appends `?leporello` query parameter to your HTML file, so you can
test if HTML file is run in Leporello.js or in production. test if HTML file is run in Leporello.js or in production.
You can add javascript libraries by including `script` tag to HTML file. If the library is exposing globals, they will be available in your javascript code after you select that HTML file as an entrypoint.
## Run and debug UI code in separate window ## Run and debug UI code in separate window
By default your code is run in invisible iframe. If you want to run and debug By default your code is run in invisible iframe. If you want to run and debug

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 KiB

After

Width:  |  Height:  |  Size: 925 KiB

View File

@@ -161,28 +161,6 @@
overflow: auto; overflow: auto;
} }
.entrypoint_select {
overflow: hidden;
display: flex;
width: fit-content;
align-items: center;
margin-left: auto;
min-height: 55px;
}
.entrypoint_select select {
min-width: 20px;
flex: 1;
}
.entrypoint_title {
margin-right: 0.5em;
}
.entrypoint_title:not(:first-child) {
margin-left: 1.5em;
}
.callnode { .callnode {
margin-left: 1em; margin-left: 1em;
} }
@@ -248,10 +226,20 @@
margin-left: 0em !important; margin-left: 0em !important;
} }
.files .file_title {
display: flex;
}
.files .file_title.active { .files .file_title.active {
background-color: rgb(225, 244, 253); background-color: rgb(225, 244, 253);
} }
.files .file_title .select_entrypoint {
margin-left: auto;
width: 40px;
text-align: center;
}
.files .file_title .icon { .files .file_title .icon {
display: inline-block; display: inline-block;
margin-right: 5px; margin-right: 5px;
@@ -259,13 +247,27 @@
} }
.file_actions { .file_actions {
position: relative;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-evenly; justify-content: flex-start;
align-items: center;
padding: 5px; padding: 5px;
background-color: rgb(225 244 253 / 80%); background-color: rgb(225 244 253 / 80%);
} }
.file_actions .file_action {
margin-right: 2em;
}
.file_actions .select_entrypoint_title {
width: 40px;
position: absolute;
right: 7px;
font-size: 0.8em;
text-align: center;
}
/* value_explorer */ /* value_explorer */
.embed_value_explorer_container { .embed_value_explorer_container {

View File

@@ -1,7 +1,10 @@
import {el} from './domutils.js' import {el} from './domutils.js'
import {map_find} from '../utils.js' import {map_find} from '../utils.js'
import {load_dir, create_file} from '../filesystem.js' import {load_dir, create_file} from '../filesystem.js'
import {exec, get_state, open_directory} from '../index.js' import {exec, get_state, open_directory, reload_run_window} from '../index.js'
const is_html = path => path.endsWith('.htm') || path.endsWith('.html')
const is_js = path => path == '' || path.endsWith('.js') || path.endsWith('.mjs')
export class Files { export class Files {
constructor(ui) { constructor(ui) {
@@ -10,6 +13,18 @@ export class Files {
this.render(get_state()) this.render(get_state())
} }
change_entrypoint(e) {
const file = e.target.value
exec('change_entrypoint', file)
this.ui.editor.focus()
}
change_html_file(e) {
const html_file = e.target.value
exec('change_html_file', html_file)
reload_run_window(get_state())
}
render(state) { render(state) {
if(state.project_dir == null) { if(state.project_dir == null) {
this.el.innerHTML = '' this.el.innerHTML = ''
@@ -25,32 +40,40 @@ export class Files {
) )
) )
} else { } else {
this.render_files(state.project_dir, state.current_module) this.render_files(state)
} }
} }
render_files(dir, current_module) { render_files(state) {
const files = this.el.querySelector('.files')
const children = [ const children = [
this.render_file({name: '*scratch*', path: ''}, current_module), this.render_file({name: '*scratch*', path: ''}, state),
this.render_file(dir, current_module), this.render_file(state.project_dir, state),
] ]
const files = this.el.querySelector('.files')
if(files == null) { if(files == null) {
this.el.innerHTML = '' this.el.innerHTML = ''
this.el.appendChild( this.el.appendChild(
el('div', 'file_actions', el('div', 'file_actions',
el('a', { el('a', {
'class': 'file_action',
href: 'javascript: void(0)', href: 'javascript: void(0)',
click: this.create_file.bind(this, false), click: this.create_file.bind(this, false),
}, },
'Create file' 'Create file'
), ),
el('a', { el('a', {
'class': 'file_action',
href: 'javascript: void(0)', href: 'javascript: void(0)',
click: this.create_file.bind(this, true), click: this.create_file.bind(this, true),
}, 'Create dir'), }, 'Create dir'),
el('a', {
href: 'https://github.com/leporello-js/leporello-js#selecting-entrypoint-module',
target: '__blank',
"class": 'select_entrypoint_title',
title: 'Select entrypoint',
}, 'Entry point'),
) )
) )
this.el.appendChild( this.el.appendChild(
@@ -64,10 +87,40 @@ export class Files {
} }
} }
render_file(file, current_module) { render_select_entrypoint(file, state) {
if(file.kind == 'directory') {
return null
} else if(is_js(file.path)) {
return el('span', 'select_entrypoint',
el('input', {
type: 'radio',
name: 'js_entrypoint',
value: file.path,
checked: state.entrypoint == file.path,
change: e => this.change_entrypoint(e),
click: e => e.stopPropagation(),
})
)
} else if(is_html(file.path)) {
return el('span', 'select_entrypoint',
el('input', {
type: 'radio',
name: 'html_file',
value: file.path,
checked: state.html_file == file.path,
change: e => this.change_html_file(e),
click: e => e.stopPropagation(),
})
)
} else {
return null
}
}
render_file(file, state) {
const result = el('div', 'file', const result = el('div', 'file',
el('div', { el('div', {
'class': 'file_title' + (file.path == current_module ? ' active' : ''), 'class': 'file_title' + (file.path == state.current_module ? ' active' : ''),
click: e => this.on_click(e, file) click: e => this.on_click(e, file)
}, },
el('span', 'icon', el('span', 'icon',
@@ -76,13 +129,14 @@ export class Files {
: '\xa0', : '\xa0',
), ),
file.name, file.name,
this.render_select_entrypoint(file, state),
), ),
file.children == null file.children == null
? null ? null
: file.children.map(c => this.render_file(c, current_module)) : file.children.map(c => this.render_file(c, state))
) )
if(file.path == current_module) { if(file.path == state.current_module) {
this.active_el = result this.active_el = result
this.active_file = file this.active_file = file
} }

View File

@@ -1,4 +1,4 @@
import {exec, get_state, open_run_window, reload_run_window} from '../index.js' import {exec, get_state, open_run_window} from '../index.js'
import {Editor} from './editor.js' import {Editor} from './editor.js'
import {Files} from './files.js' import {Files} from './files.js'
import {CallTree} from './calltree.js' import {CallTree} from './calltree.js'
@@ -8,8 +8,6 @@ import {el} from './domutils.js'
export class UI { export class UI {
constructor(container, state){ constructor(container, state){
this.change_entrypoint = this.change_entrypoint.bind(this)
this.change_html_file = this.change_html_file.bind(this)
this.open_run_window = this.open_run_window.bind(this) this.open_run_window = this.open_run_window.bind(this)
this.files = new Files(this) this.files = new Files(this)
@@ -42,7 +40,6 @@ export class UI {
href: 'javascript: void(0)', href: 'javascript: void(0)',
}, 'IO trace (F4)') }, 'IO trace (F4)')
), ),
this.entrypoint_select = el('div', 'entrypoint_select')
), ),
this.debugger.calltree = el('div', { this.debugger.calltree = el('div', {
'class': 'tab_content', 'class': 'tab_content',
@@ -58,12 +55,10 @@ export class UI {
}), }),
), ),
this.debugger_loading = el('div', 'debugger_wrapper', this.debugger_loading = el('div', 'debugger_wrapper',
el('div', 'entrypoint_select'),
this.debugger_loading_message = el('div'), this.debugger_loading_message = el('div'),
), ),
), ),
this.problems_container = el('div', {"class": 'problems_container', tabindex: 0}, this.problems_container = el('div', {"class": 'problems_container', tabindex: 0},
el('div', 'entrypoint_select'),
this.problems = el('div'), this.problems = el('div'),
) )
), ),
@@ -194,7 +189,6 @@ export class UI {
// instead // instead
this.debugger.calltree.addEventListener('click', jump_to_fn_location) this.debugger.calltree.addEventListener('click', jump_to_fn_location)
this.render_entrypoint_select(state)
this.render_current_module(state.current_module) this.render_current_module(state.current_module)
this.set_active_tab('calltree', true) this.set_active_tab('calltree', true)
@@ -216,72 +210,10 @@ export class UI {
} }
} }
render_entrypoint_select(state) {
for(let select of this.root.getElementsByClassName('entrypoint_select')) {
this.do_render_entrypoint_select(state, select)
}
}
do_render_entrypoint_select(state, select) {
select.replaceChildren(
el('span', 'entrypoint_title', 'js entrypoint'),
el('select', {
click: e => e.stopPropagation(),
change: this.change_entrypoint,
},
Object
.keys(state.files)
.sort()
.filter(f => f == '' || f.endsWith('.js') || f.endsWith('.mjs'))
.map(f =>
el('option',
state.entrypoint == f
? { value: f, selected: true }
: { value: f},
f == '' ? "*scratch*" : f
)
)
),
el('span', 'entrypoint_title', 'html page'),
el('select', {
click: e => e.stopPropagation(),
change: this.change_html_file,
},
['']
.concat(
Object
.keys(state.files)
.sort()
.filter(f => f.endsWith('.htm') || f.endsWith('.html'))
)
.map(f =>
el('option',
state.html_file == f
? { value: f, selected: true }
: { value: f},
f == '' ? 'about:blank' : f
)
)
),
)
}
open_run_window() { open_run_window() {
open_run_window(get_state()) open_run_window(get_state())
} }
change_entrypoint(e) {
const file = e.target.value
exec('change_entrypoint', file)
this.editor.focus()
}
change_html_file(e) {
const html_file = e.target.value
exec('change_html_file', html_file)
reload_run_window(get_state())
}
render_debugger_loading(state) { render_debugger_loading(state) {
this.debugger_container.style = '' this.debugger_container.style = ''
this.problems_container.style = 'display: none' this.problems_container.style = 'display: none'

10
src/effects.js vendored
View File

@@ -140,16 +140,6 @@ export const apply_side_effects = (prev, next, command, ui) => {
ui.files.render(next) ui.files.render(next)
} }
if(
prev.project_dir != next.project_dir
||
prev.entrypoint != next.entrypoint
||
prev.html_file != next.html_file
) {
ui.render_entrypoint_select(next)
}
if(prev.current_module != next.current_module) { if(prev.current_module != next.current_module) {
localStorage.current_module = next.current_module localStorage.current_module = next.current_module
ui.render_current_module(next.current_module) ui.render_current_module(next.current_module)