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

📰 Preview in frontmatter editor #2688

Merged
merged 2 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 3 additions & 6 deletions frontend/common/useDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@ export const useDialog = ({ light_dismiss = false } = {}) => {
if (dialog_ref.current != null) dialogPolyfill.registerDialog(dialog_ref.current)
}, [dialog_ref.current])

//@ts-ignore
const open = () => dialog_ref.current.showModal()
//@ts-ignore
const close = () => dialog_ref.current.close()
//@ts-ignore
const toggle = () => (dialog_ref.current.open ? dialog_ref.current?.close() : dialog_ref.current?.showModal())
const open = () => dialog_ref.current?.showModal()
const close = () => dialog_ref.current?.close()
const toggle = () => (dialog_ref.current?.open === true ? dialog_ref.current?.close() : dialog_ref.current?.showModal())

useEffect(() => {
if (light_dismiss) {
Expand Down
3 changes: 2 additions & 1 deletion frontend/components/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1562,7 +1562,8 @@ patch: ${JSON.stringify(
)}
/>
<${EditorLaunchBackendButton} editor=${this} launch_params=${launch_params} status=${status} />
<${FrontMatterInput}
<${FrontMatterInput}
filename=${notebook.shortpath}
remote_frontmatter=${notebook.metadata?.frontmatter}
set_remote_frontmatter=${(newval) =>
this.actions.update_notebook((nb) => {
Expand Down
21 changes: 19 additions & 2 deletions frontend/components/FrontmatterInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import "https://cdn.jsdelivr.net/gh/fonsp/[email protected]/lib/rebel-tag-in
import dialogPolyfill from "https://cdn.jsdelivr.net/npm/[email protected]/dist/dialog-polyfill.esm.min.js"
import immer from "../imports/immer.js"
import { useDialog } from "../common/useDialog.js"
import { FeaturedCard } from "./welcome/FeaturedCard.js"

/**
* @param {{
* filename: String,
* remote_frontmatter: Record<String,any>?,
* set_remote_frontmatter: (newval: Record<String,any>) => Promise<void>,
* }} props
* */
export const FrontMatterInput = ({ remote_frontmatter, set_remote_frontmatter }) => {
export const FrontMatterInput = ({ filename, remote_frontmatter, set_remote_frontmatter }) => {
const [frontmatter, set_frontmatter] = useState(remote_frontmatter ?? {})

useEffect(() => {
Expand Down Expand Up @@ -138,6 +140,19 @@ export const FrontMatterInput = ({ remote_frontmatter, set_remote_frontmatter })
If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and
social media.
</p>
<div class="card-preview">
<h2>Preview</h2>
<${FeaturedCard}
entry=${
/** @type {import("./welcome/Featured.js").SourceManifestNotebookEntry} */ ({
id: filename.replace(/\.jl$/, ""),
hash: "xx",
frontmatter,
})
}
disable_links=${true}
/>
</div>
<div class="fm-table">
${entries_input(frontmatter_with_defaults, ``)}
${!_.isArray(frontmatter_with_defaults.author)
Expand Down Expand Up @@ -205,11 +220,13 @@ const Input = ({ value, on_value, type, id }) => {
}
}, [input_ref.current])

const placeholder = type === "url" ? "https://..." : undefined

return type === "tags"
? html`<rbl-tag-input id=${id} ref=${input_ref} />`
: type === "license"
? LicenseInput({ ref: input_ref, id })
: html`<input type=${type} id=${id} ref=${input_ref} />`
: html`<input type=${type} id=${id} ref=${input_ref} placeholder=${placeholder} />`
}

// https://choosealicense.com/licenses/
Expand Down
19 changes: 12 additions & 7 deletions frontend/components/welcome/FeaturedCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@ const str_to_degree = (s) => ([...s].reduce((a, b) => a + b.charCodeAt(0), 0) *

/**
* @param {{
* source_manifest: import("./Featured.js").SourceManifest,
* source_manifest?: import("./Featured.js").SourceManifest,
* entry: import("./Featured.js").SourceManifestNotebookEntry,
* direct_html_links: boolean,
* disable_links: boolean,
* }} props
*/
export const FeaturedCard = ({ entry, source_manifest, direct_html_links }) => {
export const FeaturedCard = ({ entry, source_manifest, direct_html_links, disable_links }) => {
const title = entry.frontmatter?.title

const { source_url } = source_manifest
const { source_url } = source_manifest ?? {}

const u = (/** @type {string | null | undefined} */ x) =>
source_url == null
? x
? _.isEmpty(x)
? null
: x
: x == null
? null
: // URLs are relative to the source URL...
Expand All @@ -32,7 +35,9 @@ export const FeaturedCard = ({ entry, source_manifest, direct_html_links }) => {
).href

// `direct_html_links` means that we will navigate you directly to the exported HTML file. Otherwise, we use our local editor, with the exported state as parameters. This lets users run the featured notebooks locally.
const href = direct_html_links
const href = disable_links
? "#"
: direct_html_links
? u(entry.html_path)
: with_query_params(`edit`, {
statefile: u(entry.statefile_path),
Expand All @@ -41,7 +46,7 @@ export const FeaturedCard = ({ entry, source_manifest, direct_html_links }) => {
disable_ui: `true`,
name: title == null ? null : `sample ${title}`,
pluto_server_url: `.`,
slider_server_url: u(source_manifest.slider_server_url),
slider_server_url: u(source_manifest?.slider_server_url),
})

const author = author_info(entry.frontmatter)
Expand Down Expand Up @@ -96,7 +101,7 @@ const author_info_item = (x) => {
} else if (x instanceof Object) {
let { name, image, url } = x

if (image == null && url != null) {
if (image == null && !_.isEmpty(url)) {
image = url + ".png?size=48"
}

Expand Down
15 changes: 15 additions & 0 deletions frontend/editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
@import url("./light_color.css");
@import url("./dark_color.css");

@import url("./featured-card.css");

/* VARIABLES */

:root {
Expand Down Expand Up @@ -3501,6 +3503,19 @@ pluto-cell.hooked_up pluto-output {
padding: 1em 1.5em;
}

.pluto-frontmatter .card-preview {
background: var(--white);
padding: 1.2rem 1.1rem;
margin: 1rem 0;
box-shadow: inset 0px 0px 15px -4px #00000054;
border-radius: 1rem;
}

.pluto-frontmatter .card-preview > h2 {
margin-block-start: 0;
color: var(--black);
}

.pluto-frontmatter button {
cursor: pointer;
background-color: var(--frontmatter-button-bg-color);
Expand Down
142 changes: 142 additions & 0 deletions frontend/featured-card.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
:root {
--card-width: 15rem;
}

featured-card {
--card-color: hsl(var(--card-color-hue), 77%, 82%);
--card-border-radius: 10px;
--card-border-width: 3px;

display: block;
/* width: var(--card-width); */
border: var(--card-border-width) solid var(--card-color);
border-radius: var(--card-border-radius);
margin: 10px;
padding-bottom: 0.3rem;
box-shadow: 0px 2px 6px 0px #00000014;
font-family: var(--inter-ui-font-stack);
position: relative;
word-break: break-word;
hyphens: auto;
background: var(--index-card-bg);
max-width: var(--card-width);
}

featured-card .banner img {
--zz: calc(var(--card-border-radius) - var(--card-border-width));
width: 100%;
/* height: 8rem; */
aspect-ratio: 3/2;
object-fit: cover;
/* background-color: hsl(16deg 100% 66%); */
background: var(--card-color);
border-radius: var(--zz) var(--zz) 0 0;
flex: 1 1 200px;
min-width: 0;
}

featured-card a {
text-decoration: none;
/* font-weight: 800; */
}

featured-card a.banner {
display: flex;
}

featured-card .author {
font-weight: 600;
}

featured-card .author {
position: absolute;
top: 0.3em;
right: 0.3em;
background: var(--welcome-card-author-backdrop);
/* background: hsl(var(--card-color-hue) 34% 46% / 59%); */
backdrop-filter: blur(15px);
color: black;
border-radius: 117px;
/* height: 2.5em; */
padding: 0.3em;
padding-right: 0.8em;
display: flex;
}

featured-card .author img {
--size: 1.6em;
/* margin: 0.4em 0.4em; */
/* margin-bottom: -0.4em; */
width: var(--size);
height: var(--size);
object-fit: cover;
border-radius: 100%;
background: #b6b6b6;
display: inline-block;
overflow: hidden;
}

featured-card .author a {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.4ch;
}

featured-card h3 a {
padding: 0.6em;
padding-bottom: 0;
-webkit-line-clamp: 2;
display: inline-block;
display: -webkit-inline-box;
-webkit-box-orient: vertical;
overflow: hidden;
background: var(--index-card-bg);
border-radius: 0.6em;
/* border-top-left-radius: 0; */
}

featured-card p {
margin: 0.3rem 0.8rem;
/* padding-top: 0; */
/* margin-block: 0; */
color: #838383;
-webkit-line-clamp: 4;
display: inline-block;
display: -webkit-inline-box;
-webkit-box-orient: vertical;
overflow: hidden;
}

featured-card h3 {
margin: -1.1rem 0rem 0rem 0rem;
}

featured-card.big {
grid-column-end: span 2;
grid-row-end: span 2;
/* width: 2000px; */
}

featured-card.big .banner img {
height: 16rem;
}

featured-card.special::before {
content: "New!";
font-size: 1.4rem;
font-weight: 700;
text-transform: uppercase;
font-style: italic;
display: block;
background: #fcf492;
color: #833bc6;
text-shadow: 0 0 1px #ff6767;
position: absolute;
transform: translateY(calc(-100% - -15px)) rotate(-5deg);
padding: 2px 19px;
left: -9px;
/* right: 51px; */
/* border: 2px solid #ffca62; */
pointer-events: none;
}
Loading