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

🌟 Featured notebooks & new main menu #2048

Merged
merged 66 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
525f484
hello
fonsp Apr 5, 2022
cbfeb71
CSS 💕💕💕
fonsp Apr 5, 2022
1326c00
featured sources integrity
fonsp Apr 6, 2022
fcffb1a
launch param: pluto_server_url
fonsp Apr 6, 2022
bb2b8da
Merge branch 'main' into featured-notebooks
fonsp Apr 6, 2022
cc03e63
RunLocal button
fonsp Apr 6, 2022
31d9900
Update RunLocal.js
fonsp Apr 6, 2022
cf4731a
Merge branch 'main' into featured-notebooks
fonsp Apr 6, 2022
99919d3
Update Editor.js
fonsp Apr 6, 2022
350cda9
Merge branch 'main' into featured-notebooks
fonsp Apr 6, 2022
bc12909
asdf
fonsp Apr 11, 2022
233568e
asdf
fonsp Apr 14, 2022
05a506b
Merge branch 'featured-notebooks' into index-redesign-1
fonsp Apr 14, 2022
16bff37
safd
fonsp Apr 14, 2022
ee6622a
asdf
fonsp Apr 14, 2022
931a72c
mooie kleurjtes
fonsp Apr 14, 2022
55dad2d
fix stacking context
fonsp Apr 19, 2022
16fa3ff
Merge branch 'main' into featured-notebooks
fonsp Apr 19, 2022
fd5e713
file picker sizing
fonsp Apr 19, 2022
dca6fd7
Update index.html
fonsp Apr 19, 2022
0e9a6c7
Merge branch 'main' into featured-notebooks
fonsp Apr 19, 2022
0083c64
dark mode
fonsp Apr 20, 2022
5b29f14
Merge branch 'main' into featured-notebooks
fonsp Apr 21, 2022
854e6eb
collections
fonsp Apr 21, 2022
47c65e3
Merge branch 'main' into featured-notebooks
fonsp Apr 21, 2022
92ab863
merge part 2
fonsp Apr 21, 2022
0245f1a
tweaks and loading improvements
fonsp Apr 21, 2022
d42d4be
offline fallback
fonsp Apr 21, 2022
89dc32f
wrong file
fonsp Apr 21, 2022
d662924
asdf
fonsp Apr 22, 2022
c4dce07
URLTools.js
fonsp Apr 22, 2022
6c8ed0f
tweaks
fonsp Apr 22, 2022
53363e6
Merge branch 'main' into featured-notebooks
fonsp Apr 22, 2022
517ca1d
merge part 2
fonsp Apr 22, 2022
bce7a3b
Hide path from statefile generation
fonsp Apr 22, 2022
4bd51bd
use notebook title as sample filename
fonsp Apr 22, 2022
4b9df5d
RunLocal notebookfile_integrity
fonsp Apr 22, 2022
e3a727c
Merge branch 'main' into featured-notebooks
fonsp Apr 22, 2022
4c2e6cd
integrity check for notebookfile
fonsp Apr 22, 2022
dfd3360
Update Editor.js
fonsp Apr 25, 2022
a45546c
Merge branch 'main' into featured-notebooks
fonsp Apr 27, 2022
3a94a63
card redesign
fonsp Apr 27, 2022
d4b4379
refactor error page
fonsp Apr 27, 2022
43ae42b
Update index.css
fonsp Apr 27, 2022
1f65141
Merge branch 'main' into featured-notebooks
fonsp Apr 27, 2022
e3176cf
gfhjk
fonsp Apr 28, 2022
838b0f3
Update index.css
fonsp Apr 28, 2022
f388421
scrollbar tweaks
fonsp May 9, 2022
4ba01e8
Merge branch 'main' into featured-notebooks
fonsp May 18, 2022
44d6e08
Merge branch 'featured-notebooks' of https://github.com/fonsp/Pluto.j…
fonsp May 25, 2022
f182523
Merge branch 'main' into featured-notebooks
fonsp Jun 16, 2022
b02c3cc
fix card image
fonsp Jun 16, 2022
e162a33
update sources
fonsp Jun 16, 2022
89f853f
update to new format
fonsp Jun 16, 2022
ce86ee3
whitespace
fonsp Jun 16, 2022
7595814
whitespace
fonsp Jun 16, 2022
6fa6b36
Merge branch 'main' into featured-notebooks
fonsp Jun 16, 2022
b6979b2
Update RunLocal.js
fonsp Jun 16, 2022
b07cf80
Merge branch 'main' into featured-notebooks
fonsp Jun 16, 2022
ceee927
binder&local launch: show error message on failure
fonsp Jun 16, 2022
1d22159
fix
fonsp Jun 16, 2022
c0ed83f
move sources to js file
fonsp Jun 16, 2022
a7d2826
Update sample license info in readme
fonsp Jun 16, 2022
6ca50d7
Update README.md
fonsp Jun 16, 2022
40b33a8
back button
fonsp Jun 16, 2022
6777721
update sources
fonsp Jun 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ Lastly, here's _**one more feature**_: Pluto notebooks have a `@bind` macro to c

<br >

You don't need to know HTML to use it! The [PlutoUI package](https://github.com/fonsp/PlutoUI.jl) contains basic inputs like sliders and buttons. Pluto's interactivity is very easy to use, you will learn more from the sample notebooks inside Pluto!
You don't need to know HTML to use it! The [PlutoUI package](https://github.com/fonsp/PlutoUI.jl) contains basic inputs like sliders and buttons. Pluto's interactivity is very easy to use, you will learn more from the featured notebooks inside Pluto!

But for those who want to dive deeper - you can use HTML, JavaScript and CSS to write your own widgets! Custom update events can be fired by dispatching a `new CustomEvent("input")`, making it compatible with the [`viewof` operator of observablehq](https://observablehq.com/@observablehq/a-brief-introduction-to-viewof). Have a look at the JavaScript sample notebook inside Pluto!
But for those who want to dive deeper - you can use HTML, JavaScript and CSS to write your own widgets! Custom update events can be fired by dispatching a `new CustomEvent("input")`, making it compatible with the [`viewof` operator of observablehq](https://observablehq.com/@observablehq/a-brief-introduction-to-viewof). Have a look at the JavaScript featured notebook inside Pluto!

<br >

Expand Down Expand Up @@ -160,9 +160,9 @@ Pluto.jl is open source! Specifically, it is [MIT Licensed](https://github.com/f

If you want to reference Pluto.jl in scientific writing, you can use our DOI: [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4792401.svg)](https://doi.org/10.5281/zenodo.4792401)

### Sample notebooks
### Featured notebooks

The included sample notebooks have a more permissive license: the [Unlicense](https://github.com/fonsp/Pluto.jl/blob/main/sample/LICENSE). This means that you can use sample notebook code however you like - you do not need to credit us!
Unless otherwise specified, the included featured notebooks have a more permissive license: the [Unlicense](https://github.com/fonsp/Pluto.jl/blob/main/sample/LICENSE). This means that you can use them however you like - you do not need to credit us!

Your notebook files are _yours_, you also do not need to credit us. Have fun!

Expand Down
4 changes: 2 additions & 2 deletions frontend-bundler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"version": "1.0.0",
"description": "",
"scripts": {
"start": "cd ../frontend && parcel --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html sample.html",
"build": "cd ../frontend && parcel build --no-source-maps --public-url . --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html sample.html && node ../frontend-bundler/add_sri.js ../frontend-dist/editor.html",
"start": "cd ../frontend && parcel --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html",
"build": "cd ../frontend && parcel build --no-source-maps --public-url . --dist-dir ../frontend-dist --config ../frontend-bundler/.parcelrc editor.html index.html error.jl.html && node ../frontend-bundler/add_sri.js ../frontend-dist/editor.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
Expand Down
21 changes: 17 additions & 4 deletions frontend/common/Binder.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,17 @@ export const start_binder = async ({ setStatePromise, connect, launch_params })
let open_response = new Response()

if (launch_params.notebookfile.startsWith("data:")) {
open_response = await fetch(with_token(new URL("notebookupload", binder_session_url)), {
method: "POST",
body: await (await fetch(new Request(launch_params.notebookfile, { integrity: launch_params.notebookfile_integrity }))).arrayBuffer(),
})
open_response = await fetch(
with_token(
with_query_params(new URL("notebookupload", binder_session_url), {
name: new URLSearchParams(window.location.search).get("name"),
})
),
{
method: "POST",
body: await (await fetch(new Request(launch_params.notebookfile, { integrity: launch_params.notebookfile_integrity }))).arrayBuffer(),
}
)
} else {
for (const [p1, p2] of [
["path", launch_params.notebookfile],
Expand All @@ -145,6 +152,12 @@ export const start_binder = async ({ setStatePromise, connect, launch_params })
}
}

if (!open_response.ok) {
let b = await open_response.blob()
window.location.href = URL.createObjectURL(b)
return
}

// Opening a notebook gives us the notebook ID, which means that we have a running session! Time to connect.

const new_notebook_id = await open_response.text()
Expand Down
3 changes: 2 additions & 1 deletion frontend/common/Bond.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export const set_bound_elements_to_their_value = (bond_nodes, bond_values) => {
export const add_bonds_disabled_message_handler = (bond_nodes, invalidation) => {
bond_nodes.forEach((bond_node) => {
const listener = (e) => {
if (e.target.closest(".bonds_disabled.offer_binder")) {
if (e.target.closest(".bonds_disabled:where(.offer_binder, .offer_local)")) {
open_pluto_popup({
type: "info",
source_element: e.target,
Expand All @@ -163,6 +163,7 @@ export const add_bonds_disabled_message_handler = (bond_nodes, invalidation) =>
//@ts-ignore
window.open_edit_or_run_popup()
e.preventDefault()
window.dispatchEvent(new CustomEvent("close pluto popup"))
}}
>Run this notebook</a
>
Expand Down
80 changes: 80 additions & 0 deletions frontend/common/RunLocal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import immer from "../imports/immer.js"
import { BackendLaunchPhase } from "./Binder.js"
import { timeout_promise } from "./PlutoConnection.js"
import { with_query_params } from "./URLTools.js"

// This file is very similar to `start_binder` in Binder.js

/**
*
* @param {{
* launch_params: import("../components/Editor.js").LaunchParameters,
* setStatePromise: any,
* connect: () => Promise<void>,
* }} props
*/
export const start_local = async ({ setStatePromise, connect, launch_params }) => {
try {
if (launch_params.pluto_server_url == null || launch_params.notebookfile == null) throw Error("Invalid launch parameters for starting locally.")

await setStatePromise(
immer((state) => {
state.backend_launch_phase = BackendLaunchPhase.created
state.disable_ui = false
})
)

const with_token = (x) => String(x)
const binder_session_url = new URL(launch_params.pluto_server_url, window.location.href)

let open_response

// We download the notebook file contents, and then upload them to the Pluto server.
const notebook_contents = await (
await fetch(new Request(launch_params.notebookfile, { integrity: launch_params.notebookfile_integrity ?? undefined }))
).arrayBuffer()

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",
})
),
{
method: "POST",
body: notebook_contents,
}
)

if (!open_response.ok) {
let b = await open_response.blob()
window.location.href = URL.createObjectURL(b)
return
}

const new_notebook_id = await open_response.text()
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)

await setStatePromise(
immer((state) => {
state.notebook.notebook_id = new_notebook_id
state.backend_launch_phase = BackendLaunchPhase.notebook_running
})
)
console.log("Connecting WebSocket")

const connect_promise = connect()
await timeout_promise(connect_promise, 20_000).catch((e) => {
console.error("Failed to establish connection within 20 seconds. Navigating to the edit URL directly.", e)

window.parent.location.href = with_token(edit_url)
})
} catch (err) {
console.error("Failed to initialize binder!", err)
alert("Something went wrong! 😮\n\nWe failed to open this notebook. Please try again with a different browser, or come back later.")
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import { BackendLaunchPhase } from "../common/Binder.js"
import { html, useEffect, useState, useRef } from "../imports/Preact.js"

export const RunLocalButton = ({ show, start_local }) => {
//@ts-ignore
window.open_edit_or_run_popup = () => {
start_local()
}

return html`<div class="edit_or_run">
<button
onClick=${(e) => {
e.stopPropagation()
e.preventDefault()
start_local()
}}
>
<b>Edit</b> or <b>run</b> this notebook
</button>
</div>`
}

export const BinderButton = ({ offer_binder, start_binder, notebookfile }) => {
const [popupOpen, setPopupOpen] = useState(false)
const [showCopyPopup, setShowCopyPopup] = useState(false)
Expand Down
32 changes: 27 additions & 5 deletions frontend/components/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ import { has_ctrl_or_cmd_pressed, ctrl_or_cmd_name, is_mac_keyboard, in_textarea
import { PlutoActionsContext, PlutoBondsContext, PlutoJSInitializingContext, SetWithEmptyCallback } from "../common/PlutoContext.js"
import { start_binder, BackendLaunchPhase, count_stat } from "../common/Binder.js"
import { setup_mathjax } from "../common/SetupMathJax.js"
import { BinderButton } from "./BinderButton.js"
import { BinderButton, RunLocalButton } from "./EditOrRunButton.js"
import { slider_server_actions, nothing_actions } from "../common/SliderServerClient.js"
import { ProgressBar } from "./ProgressBar.js"
import { IsolatedCell } from "./Cell.js"
import { RawHTMLContainer } from "./CellOutput.js"
import { RecordingPlaybackUI, RecordingUI } from "./RecordingUI.js"
import { HijackExternalLinksToOpenInNewTab } from "./HackySideStuff/HijackExternalLinksToOpenInNewTab.js"
import { start_local } from "../common/RunLocal.js"
import { FrontMatterInput } from "./FrontmatterInput.js"

// This is imported asynchronously - uncomment for development
// import environment from "../common/Environment.js"

export const default_path = "..."
export const default_path = ""
const DEBUG_DIFFING = false

// Be sure to keep this in sync with DEFAULT_CELL_METADATA in Cell.jl
Expand Down Expand Up @@ -88,6 +89,7 @@ const statusmap = (/** @type {EditorState} */ state, /** @type {LaunchParameters
static_preview: state.static_preview,
bonds_disabled: !(state.connected || state.initializing || launch_params.slider_server_url != null),
offer_binder: state.backend_launch_phase === BackendLaunchPhase.wait_for_user && launch_params.binder_url != null,
offer_local: state.backend_launch_phase === BackendLaunchPhase.wait_for_user && launch_params.pluto_server_url != null,
binder: launch_params.binder_url != null && state.backend_launch_phase != null,
code_differs: state.notebook.cell_order.some(
(cell_id) => state.cell_inputs_local[cell_id] != null && state.notebook.cell_inputs[cell_id].code !== state.cell_inputs_local[cell_id].code
Expand Down Expand Up @@ -191,6 +193,7 @@ const first_true_key = (obj) => {
* preamble_html: string?,
* isolated_cell_ids: string[]?,
* binder_url: string?,
* pluto_server_url: string?,
* slider_server_url: string?,
* recording_url: string?,
* recording_url_integrity: string?,
Expand Down Expand Up @@ -288,7 +291,10 @@ export class Editor extends Component {

disable_ui: launch_params.disable_ui,
static_preview: launch_params.statefile != null,
backend_launch_phase: launch_params.notebookfile != null && launch_params.binder_url != null ? BackendLaunchPhase.wait_for_user : null,
backend_launch_phase:
launch_params.notebookfile != null && (launch_params.binder_url != null || launch_params.pluto_server_url != null)
? BackendLaunchPhase.wait_for_user
: null,
binder_session_url: null,
binder_session_token: null,
connected: false,
Expand Down Expand Up @@ -1212,7 +1218,11 @@ patch: ${JSON.stringify(
initializing: false,
})
// view stats on https://stats.plutojl.org/
count_stat(`article-view`)
if (this.state.pluto_server_url != null) {
count_stat(`article-view`)
} else {
count_stat(`article-view`)
}
} else {
this.connect()
}
Expand Down Expand Up @@ -1315,6 +1325,9 @@ patch: ${JSON.stringify(
<${PlutoActionsContext.Provider} value=${this.actions}>
<${PlutoBondsContext.Provider} value=${this.state.notebook.bonds}>
<${PlutoJSInitializingContext.Provider} value=${this.js_init_set}>
<button title="Go back" onClick=${() => {
history.back()
}} class="floating_back_button"><span></span></button>
<${Scroller} active=${this.state.scroller} />
<${ProgressBar} notebook=${this.state.notebook} backend_launch_phase=${this.state.backend_launch_phase} status=${status}/>
<header id="pluto-nav" className=${export_menu_open ? "show_export" : ""}>
Expand Down Expand Up @@ -1408,7 +1421,16 @@ patch: ${JSON.stringify(
/>

${
status.offer_binder
status.offer_local
? html`<${RunLocalButton}
start_local=${() =>
start_local({
setStatePromise: this.setStatePromise,
connect: this.connect,
launch_params: launch_params,
})}
/>`
: status.offer_binder
? html`<${BinderButton}
offer_binder=${status.offer_binder}
start_binder=${() =>
Expand Down
10 changes: 8 additions & 2 deletions frontend/components/Popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,32 @@ export const Popup = ({ notebook }) => {
set_recent_event(e.detail)
}

const close = () => {
set_recent_event(null)
}

useEffect(() => {
const onpointerdown = (e) => {
if (e.target == null) return
if (e.target.closest("pluto-popup") != null) return
if (recent_source_element_ref.current == null) return
if (recent_source_element_ref.current.contains(e.target)) return

set_recent_event(null)
close()
}
const onkeydown = (e) => {
if (e.key === "Escape") {
set_recent_event(null)
close()
}
}
window.addEventListener("open pluto popup", open)
window.addEventListener("close pluto popup", close)
window.addEventListener("pointerdown", onpointerdown)
document.addEventListener("keydown", onkeydown)

return () => {
window.removeEventListener("open pluto popup", open)
window.removeEventListener("close pluto popup", close)
window.removeEventListener("pointerdown", onpointerdown)
document.removeEventListener("keydown", onkeydown)
}
Expand Down
Loading