Skip to content

Commit

Permalink
📰 Preview in frontmatter editor (#2688)
Browse files Browse the repository at this point in the history
  • Loading branch information
fonsp authored Oct 30, 2023
1 parent d1ebead commit 52e471d
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 159 deletions.
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

0 comments on commit 52e471d

Please sign in to comment.