link to example

This commit is contained in:
Dmitry Vasilev
2023-07-14 03:02:10 +03:00
parent 2f34028956
commit 465bbd83f4
7 changed files with 147 additions and 40 deletions

View File

@@ -1,6 +1,5 @@
import {h, render} from 'https://unpkg.com/preact?module';
// external
import {createApp, handler, connect} from './app.js'
// Components

View File

@@ -341,6 +341,37 @@
margin-left: auto;
}
.open_app_window_button {
position: relative;
}
.open_app_window_tooltip {
padding: 1em;
position: absolute;
margin-bottom: 20px;
bottom: 100%;
border: none;
font-size: 1.7em;
background-color: rgb(120 206 247);
border-radius: 21px;
transform: scale(0);
transition: transform 0.3s;
}
.open_app_window_tooltip.on {
transform: scale(1);
}
.open_app_window_tooltip:after {
content: '';
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-top: 20px solid rgb(120 206 247);
position: absolute;
bottom: -20px;
left: 50%;
transform: translate(-50%);
}
.options {
padding: 5px;
}

View File

@@ -1,6 +1,7 @@
import {el} from './domutils.js'
import {map_find} from '../utils.js'
import {open_dir, create_file} from '../filesystem.js'
import {examples} from '../examples.js'
import {
exec,
get_state,
@@ -219,16 +220,47 @@ export class Files {
on_click(e, file) {
e.stopPropagation()
this.render_current_module(file.path)
if(file.kind != 'directory') {
if(get_state().has_file_system_access) {
if(get_state().has_file_system_access) {
if(file.kind != 'directory') {
exec('change_current_module', file.path)
} else {
// in examples mode, on click file we also change entrypoint for
// simplicity
exec('change_entrypoint', file.path)
}
} else {
if(file.path == null) {
// root of examples dir, do nothing
return
}
if(file.path == '') {
exec('change_entrypoint', '')
return
}
const find_node = n =>
n.path == file.path
||
n.children != null && n.children.find(find_node)
// find example dir
const example_dir = get_state().project_dir.children.find(
c => find_node(c) != null
)
// in examples mode, on click file we also change entrypoint for
// simplicity
const example = examples.find(e => e.path == example_dir.path)
exec('change_entrypoint', example.entrypoint)
if(example.with_app_window && !localStorage.onboarding_open_app_window) {
this.ui.toggle_open_app_window_tooltip(true)
}
}
// Note that we call render_current_module AFTER exec('change_entrypoint'),
// because in case we clicked to example dir, entrypoint would be set, and
// rendered active, so file with entrypoint would be active and not dir we
// clicked, which is weird
this.render_current_module(file.path)
}
}

View File

@@ -88,11 +88,16 @@ export class UI {
),
el('a', {
'class': 'statusbar_action',
'class': 'statusbar_action open_app_window_button',
href: 'javascript: void(0)',
click: this.open_app_window,
},
'(Re)open app window (F7)'
'(Re)open app window (F7)',
this.open_app_window_tooltip = el('div', {
'class': 'open_app_window_tooltip',
},
'Click here to open app window'
)
),
this.options = el('div', 'options',
@@ -211,6 +216,8 @@ export class UI {
}
open_app_window() {
this.toggle_open_app_window_tooltip(false)
localStorage.onboarding_open_app_window = true
open_app_window(get_state())
}
@@ -350,4 +357,8 @@ export class UI {
}
}
toggle_open_app_window_tooltip(on) {
this.open_app_window_tooltip.classList.toggle('on', on)
}
}

9
src/effects.js vendored
View File

@@ -127,9 +127,16 @@ const render_parse_result = (ui, state) => {
}
}
export const render_initial_state = (ui, state) => {
export const render_initial_state = (ui, state, example) => {
ensure_session(ui, state)
ui.editor.switch_session(state.current_module)
if(
example != null
&& example.with_app_window
&& !localStorage.onboarding_open_app_window
) {
ui.toggle_open_app_window_tooltip(true)
}
}
export const apply_side_effects = (prev, next, command, ui) => {

View File

@@ -6,17 +6,34 @@ const read_example = name => {
return localStorage['examples_' + name]
}
const list = [
'github_api/index.js',
'ethers/block_by_timestamp.js',
'ethers/index.js',
// TODO for html5 example, open run window or hint that it should be opened
]
.map(l => l.split('/'))
export const examples = [
{
path: 'github_api',
entrypoint: 'github_api/index.js',
},
{
path: 'ethers',
entrypoint: 'ethers/block_by_timestamp.js',
},
{
path: 'todos-preact',
entrypoint: 'todos-preact/index.js',
with_app_window: true,
files: [
'todos-preact/app.js',
]
},
].map(e => ({...e, entrypoint: e.entrypoint ?? e.path}))
const files_list = examples
.map(e => {
return (e.files ?? []).concat([e.entrypoint])
})
.flat()
.map(l => l.split('/'))
const get_children = path => {
const children = list.filter(l => path.every((elem, i) => elem == l[i] ))
const children = files_list.filter(l => path.every((elem, i) => elem == l[i] ))
const files = children.filter(c => c.length == path.length + 1)
const dirs = [...new Set(children
.filter(c => c.length != path.length + 1)
@@ -46,7 +63,7 @@ const get_children = path => {
})))
}
export const examples_promise = get_children([]).then(children => {
export const examples_dir_promise = get_children([]).then(children => {
return {
kind: 'directory',
name: 'examples',
@@ -54,4 +71,3 @@ export const examples_promise = get_children([]).then(children => {
children,
}
})

View File

@@ -5,7 +5,7 @@ import {
close_dir,
init_window_service_worker
} from './filesystem.js'
import {examples_promise} from './examples.js'
import {examples, examples_dir_promise} from './examples.js'
const EXAMPLE = `function fib(n) {
if(n == 0 || n == 1) {
@@ -141,20 +141,10 @@ export const reload_app_window = state => {
globalThis.app_window.location = get_html_url(state)
}
const get_entrypoint_settings = () => {
const params = new URLSearchParams(window.location.search)
const entrypoint = null
?? params.get('entrypoint')
?? localStorage.entrypoint
?? ''
return {
current_module: params.get('entrypoint') ?? localStorage.current_module ?? '',
entrypoint,
current_module: localStorage.current_module ?? '',
entrypoint: localStorage.entrypoint ?? '',
html_file: localStorage.html_file ?? '',
}
}
@@ -171,7 +161,7 @@ export const open_directory = () => {
export const close_directory = async () => {
close_dir()
exec('load_dir', await examples_promise, false, get_entrypoint_settings())
exec('load_dir', await examples_dir_promise, false, get_entrypoint_settings())
}
@@ -185,15 +175,37 @@ export const init = async (container, _COMMANDS) => {
set_error_handler(window)
const default_module = {'': localStorage.code || EXAMPLE}
let initial_state
let initial_state, entrypoint_settings
const project_dir = await open_dir(false)
let example
if(project_dir == null) {
/*
extract example from URL params and delete it
*/
const params = new URLSearchParams(window.location.search)
const example_path = params.get('example')
params.delete('example')
globalThis.history.replaceState(
null,
null,
'/' + params.toString() + window.location.hash
)
example = examples.find(e => e.path == example_path)
entrypoint_settings = example == null
? get_entrypoint_settings()
: {
current_module: example.entrypoint,
entrypoint: example.entrypoint,
}
initial_state = {
project_dir: await examples_promise,
project_dir: await examples_dir_promise,
files: default_module,
has_file_system_access: false,
}
} else {
entrypoint_settings = get_entrypoint_settings()
initial_state = {
project_dir,
files: default_module,
@@ -206,8 +218,7 @@ export const init = async (container, _COMMANDS) => {
...initial_state,
on_deferred_call: (...args) => exec('on_deferred_call', ...args)
},
get_entrypoint_settings(),
entrypoint_settings,
)
// Expose state for debugging
@@ -216,7 +227,7 @@ export const init = async (container, _COMMANDS) => {
// Expose for debugging
globalThis.__ui = ui
render_initial_state(ui, state)
render_initial_state(ui, state, example)
open_run_iframe(state)
}