Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desktop app front end changes #2651

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
17 changes: 11 additions & 6 deletions frontend/common/RunLocal.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@ export const start_local = async ({ setStatePromise, connect, launch_params }) =

open_response = await fetch(
with_token(
with_query_params(new URL("notebookupload", binder_session_url), {
name: new URLSearchParams(window.location.search).get("name"),
clear_frontmatter: "yesplease",
execution_allowed: "yepperz",
})
with_query_params(
new URL(with_query_params("notebookupload", Object.fromEntries(binder_session_url.searchParams.entries())), binder_session_url),
{
name: new URLSearchParams(window.location.search).get("name"),
clear_frontmatter: "yesplease",
execution_allowed: "yepperz",
}
)
),
{
method: "POST",
Expand All @@ -60,7 +63,9 @@ export const start_local = async ({ setStatePromise, connect, launch_params }) =
const edit_url = with_query_params(new URL("edit", binder_session_url), { id: new_notebook_id })
console.info("notebook_id:", new_notebook_id)

window.history.replaceState({}, "", edit_url)
if (!window.plutoDesktop) {
window.history.replaceState({}, "", edit_url)
}

await setStatePromise(
immer((/** @type {import("../components/Editor.js").EditorState} */ state) => {
Expand Down
6 changes: 6 additions & 0 deletions frontend/components/DesktopInterface.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const open_from_path = () => {
window.plutoDesktop?.fileSystem.openNotebook("path")
}
export const open_from_url = (/** @type string */ url) => {
window.plutoDesktop?.fileSystem.openNotebook("url", url)
}
4 changes: 2 additions & 2 deletions frontend/components/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ patch: ${JSON.stringify(

this.connect = (/** @type {string | undefined} */ ws_address = undefined) =>
create_pluto_connection({
ws_address: ws_address,
ws_address: ws_address ?? ws_address_from_base(this.props.launch_params.pluto_server_url ?? window.location.href),
on_unrequested_update: on_update,
on_connection_status: on_connection_status,
on_reconnect: on_reconnect,
Expand Down Expand Up @@ -1403,7 +1403,7 @@ patch: ${JSON.stringify(
`article-view/${window?.version_info?.pluto ?? this.state.notebook.pluto_version ?? "unknown"}`
)
} else {
this.connect(lp.pluto_server_url ? ws_address_from_base(lp.pluto_server_url) : undefined)
this.connect()
}
}

Expand Down
49 changes: 10 additions & 39 deletions frontend/components/FilePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,19 @@ const set_cm_value = (/** @type{EditorView} */ cm, /** @type {string} */ value,
}
}

const is_desktop = !!window.plutoDesktop

if (is_desktop) {
console.log("Running in Desktop Environment! Found following properties/methods:", window.plutoDesktop)
}

/**
* @param {{
* value: String,
* suggest_new_file: {base: String},
* button_label: String,
* placeholder: String,
* on_submit: (new_path: String) => Promise<void>,
* on_desktop_submit?: (loc?: string) => Promise<void>,
* client: import("../common/PlutoConnection.js").PlutoConnection,
* force_on_blur: Boolean
* }} props
*/
export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, on_submit, on_desktop_submit, client }) => {
export const FilePicker = ({ value, suggest_new_file, button_label, placeholder, on_submit, client, force_on_blur = true }) => {
const [is_button_disabled, set_is_button_disabled] = useState(true)
const [url_value, set_url_value] = useState("")
const forced_value = useRef("")
/** @type {import("../imports/Preact.js").Ref<HTMLElement>} */
const base = useRef(/** @type {any} */ (null))
Expand All @@ -89,18 +82,9 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder,
const onSubmit = () => {
const current_cm = cm.current
if (current_cm == null) return
if (!is_desktop) {
const my_val = current_cm.state.doc.toString()
if (my_val === forced_value.current) {
suggest_not_tmp()
return true
}
}
run(async () => {
try {
if (is_desktop && on_desktop_submit) {
await on_desktop_submit((await guess_notebook_location(url_value)).path_or_url)
} else await on_submit(current_cm.state.doc.toString())
await on_submit(current_cm.state.doc.toString())
current_cm.dom.blur()
} catch (error) {
set_cm_value(current_cm, forced_value.current, true)
Expand Down Expand Up @@ -143,7 +127,7 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder,
},
blur: (event, cm) => {
setTimeout(() => {
if (!cm.hasFocus) {
if (!cm.hasFocus && force_on_blur) {
set_cm_value(cm, forced_value.current, true)
}
}, 200)
Expand Down Expand Up @@ -255,7 +239,7 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder,
})
const current_cm = cm.current

if (!is_desktop) base.current.insertBefore(current_cm.dom, base.current.firstElementChild)
base.current.insertBefore(current_cm.dom, base.current.firstElementChild)
// window.addEventListener("resize", () => {
// if (!cm.current.hasFocus()) {
// deselect(cm.current)
Expand All @@ -271,24 +255,11 @@ export const FilePicker = ({ value, suggest_new_file, button_label, placeholder,
}
})

return is_desktop
? html`<div class="desktop_picker_group" ref=${base}>
<input
value=${url_value}
placeholder="Enter notebook URL..."
onChange=${(v) => {
set_url_value(v.target.value)
}}
/>
<div onClick=${onSubmit} class="desktop_picker">
<button>${button_label}</button>
</div>
</div>`
: html`
<pluto-filepicker ref=${base}>
<button onClick=${onSubmit} disabled=${is_button_disabled}>${button_label}</button>
</pluto-filepicker>
`
return html`
<pluto-filepicker ref=${base}>
<button onClick=${onSubmit} disabled=${is_button_disabled}>${button_label}</button>
</pluto-filepicker>
`
}

const pathhints =
Expand Down
68 changes: 41 additions & 27 deletions frontend/components/welcome/Open.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import _ from "../../imports/lodash.js"
import { html } from "../../imports/Preact.js"
import { html, useState } from "../../imports/Preact.js"

import { FilePicker } from "../FilePicker.js"
import { PasteHandler } from "../PasteHandler.js"
import { guess_notebook_location } from "../../common/NotebookLocationFromURL.js"

import * as desktop from "../DesktopInterface.js"

/**
* @param {{
* client: import("../../common/PlutoConnection.js").PlutoConnection?,
Expand All @@ -21,40 +23,52 @@ export const Open = ({ client, connected, CustomPicker, show_samples, on_start_n
window.location.href = (processed.type === "path" ? link_open_path : link_open_url)(processed.path_or_url)
}

const desktop_on_open_path = async (_p) => {
window.plutoDesktop?.fileSystem.openNotebook("path")
}

const desktop_on_open_url = async (url) => {
window.plutoDesktop?.fileSystem.openNotebook("url", url)
}

const picker = CustomPicker ?? {
text: "Open a notebook",
placeholder: "Enter path or URL...",
}

// may be passed to FilePicker to disable autocomplete by spoofing an autocompletion client
const dummy_client = {
send: (_) => {
return {
then: (_) => {},
}
},
}

return html`<${PasteHandler} on_start_navigation=${on_start_navigation} />
<h2>${picker.text}</h2>
<div id="new" class=${!!window.plutoDesktop ? "desktop_opener" : ""}>
<${FilePicker}
key=${picker.placeholder}
client=${client}
value=""
on_submit=${on_open_path}
on_desktop_submit=${desktop_on_open_path}
button_label=${window.plutoDesktop ? "Open File" : "Open"}
placeholder=${picker.placeholder}
/>
${window.plutoDesktop &&
html`<${FilePicker}
key=${picker.placeholder}
client=${client}
value=""
on_desktop_submit=${desktop_on_open_url}
button_label="Open from URL"
placeholder=${picker.placeholder}
/>`}
${window.plutoDesktop
? html`
<div class="desktop_picker_group">
<button onClick=${desktop.open_from_path}>Open File</button>
<div class="option_splitter">— OR —</div>
<div>
<${FilePicker}
key=${picker.placeholder}
client=${client}
value=""
on_submit=${desktop.open_from_url}
button_label=${"Open from URL"}
placeholder=${"Enter a URL..."}
client=${dummy_client}
force_on_blur=${false}
/>
</div>
</div>
`
: html`
<${FilePicker}
key=${picker.placeholder}
client=${client}
value=""
on_submit=${on_open_path}
button_label=${window.plutoDesktop ? "Open File" : "Open"}
placeholder=${picker.placeholder}
/>
`}
</div>`
}

Expand Down
6 changes: 6 additions & 0 deletions frontend/components/welcome/Welcome.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ export const Welcome = ({ launch_params }) => {
})
}, [])

useEffect(() => {
window.plutoDesktop?.ipcRenderer.on("set-block-screen-text", (/** @type string */ block_screen_text) => {
set_block_screen_with_this_text(block_screen_text)
})
}, [])

const { show_samples, CustomRecent, CustomPicker } = extended_components

// When block_screen_with_this_text is null (default), all is fine. When it is a string, we show a big banner with that text, and disable all other UI. https://github.com/fonsp/Pluto.jl/pull/2292
Expand Down
35 changes: 27 additions & 8 deletions frontend/editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -690,16 +690,34 @@ nav#at_the_top img#logo-small {
}
}

.desktop_picker button {
background: var(--footer-filepicker-focus-color);
border-radius: 3px;
border: 2px solid var(--nav-filepicker-focus-color);
color: var(--white);
font-family: "Roboto Mono", monospace;
font-weight: 600;
font-size: 0.75rem;
}

nav#at_the_top > div.desktop_picker_group span {
padding: 0 5px;
white-space: nowrap;
display: inline-flex;
align-items: center;
overflow: hidden;
}

nav#at_the_top > pluto-filepicker,
nav#at_the_top > div.desktop_picker {
nav#at_the_top > div.desktop_picker_group {
width: 210px;
flex-grow: 1;
display: flex;
flex-direction: row;
}

nav#at_the_top > pluto-filepicker .cm-editor,
nav#at_the_top > div.desktop_picker span {
div.desktop_picker_group span {
height: calc(1rem + 4px + 4px + 4px);
display: inline-block;
min-width: 10rem;
Expand Down Expand Up @@ -811,27 +829,27 @@ nav#at_the_top:after {

@media (any-pointer: fine) {
nav#at_the_top > pluto-filepicker .cm-editor,
nav#at_the_top > div.desktop_picker span {
nav#at_the_top > div.desktop_picker_group span {
border: 2px solid transparent;
border-right: none;
transition: border 0.15s ease-in-out;
}
nav#at_the_top > pluto-filepicker button,
nav#at_the_top > div.desktop_picker button {
nav#at_the_top > div.desktop_picker_group button {
opacity: 0;
transition: opacity 0.15s ease-in-out;
}
header:hover > nav#at_the_top > pluto-filepicker .cm-editor,
header:focus-within > nav#at_the_top > pluto-filepicker .cm-editor,
header:hover > nav#at_the_top > div.desktop_picker span,
header:focus-within > nav#at_the_top > div.desktop_picker span {
header:hover > nav#at_the_top > div.desktop_picker_group span,
header:focus-within > nav#at_the_top > div.desktop_picker_group span {
border: 2px solid var(--footer-input-border-color);
border-right: none;
}
header:hover > nav#at_the_top > pluto-filepicker button,
header:focus-within > nav#at_the_top > pluto-filepicker button,
header:hover > nav#at_the_top > div.desktop_picker button,
header:focus-within > nav#at_the_top > div.desktop_picker button {
header:hover > nav#at_the_top > div.desktop_picker_group button,
header:focus-within > nav#at_the_top > div.desktop_picker_group button {
opacity: 1;
}
}
Expand Down Expand Up @@ -2854,6 +2872,7 @@ footer input {
}

header#pluto-nav pluto-filepicker button,
header#pluto-nav .desktop_picker_group button,
footer button {
margin: 0px;
background: var(--footer-filepicker-focus-color);
Expand Down
24 changes: 14 additions & 10 deletions frontend/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pluto-filepicker .cm-scroller::-webkit-scrollbar {
}

pluto-filepicker button,
.desktop_picker button {
.desktop_picker_group button {
margin: 0px;
background: var(--footer-filepicker-focus-color);
border-radius: 3px;
Expand All @@ -132,22 +132,26 @@ pluto-filepicker button,
}

.desktop_picker_group {
display: inline-flex;
flex-grow: 1;
/* display: flex; */
padding: 5px;
}

.desktop_picker_group > input {
margin-left: 1em;
}

.desktop_picker > button {
.desktop_picker_group > button {
cursor: pointer;
padding: 8px;
width: 100%;
}

.desktop_picker > button.full_width {
width: 100%;
.desktop_picker_group > .option_splitter {
color: gray;
font-style: italic;
text-align: center;
margin: 15px 0;
font-size: 10pt;
}

pluto-filepicker button {
#new pluto-filepicker button {
cursor: pointer;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
Expand Down
Loading
Loading