diff --git a/apps/web/src/utils/web-extension-server.ts b/apps/web/src/utils/web-extension-server.ts index e88460f83..d5cd96fc4 100644 --- a/apps/web/src/utils/web-extension-server.ts +++ b/apps/web/src/utils/web-extension-server.ts @@ -73,7 +73,11 @@ export class WebExtensionServer implements Server { async saveClip(clip: Clip) { let clipContent = ""; - if (clip.mode === "simplified" || clip.mode === "screenshot") { + if ( + clip.mode === "simplified" || + clip.mode === "screenshot" || + clip.mode === "bookmark" + ) { clipContent += clip.data; } else { const clippedFile = new File( @@ -105,11 +109,17 @@ export class WebExtensionServer implements Server { if (isCipher(content)) return; content += clipContent; - content += h("div", [ - h("hr"), - h("p", ["Clipped from ", h("a", [clip.title], { href: clip.url })]), - h("p", [`Date clipped: ${getFormattedDate(Date.now())}`]) - ]).innerHTML; + content += + clip.mode === "bookmark" + ? h("div", [ + h("p", [`Date bookmarked: ${getFormattedDate(Date.now())}`]), + h("hr") + ]).innerHTML + : h("div", [ + h("hr"), + h("p", ["Clipped from ", h("a", [clip.title], { href: clip.url })]), + h("p", [`Date clipped: ${getFormattedDate(Date.now())}`]) + ]).innerHTML; const id = await db.notes.add({ id: note?.id, diff --git a/docs/help/contents/web-clipper/clipping-your-first-web-page-with-web-clipper.md b/docs/help/contents/web-clipper/clipping-your-first-web-page-with-web-clipper.md index 9e83b332c..4ae5f967f 100644 --- a/docs/help/contents/web-clipper/clipping-your-first-web-page-with-web-clipper.md +++ b/docs/help/contents/web-clipper/clipping-your-first-web-page-with-web-clipper.md @@ -73,6 +73,10 @@ The `Selected nodes` mode allows you to select exactly which nodes you want to c The clipping mode controls how the final clip should look. +### Bookmark + +`Bookmark` mode saves only the URL of the page along with the title. It is best suited to save pages for later reading/reference. + ### Simplified `Simplified` mode doesn't include any styles. It is best suited for long-form content such as articles & blogs. All clips in `Simplified` mode are saved directly as is i.e. they do not appear as web clip embeds in the Notesnook editor. diff --git a/extensions/web-clipper/src/common/bridge.ts b/extensions/web-clipper/src/common/bridge.ts index 3e081fb62..894c76fae 100644 --- a/extensions/web-clipper/src/common/bridge.ts +++ b/extensions/web-clipper/src/common/bridge.ts @@ -21,7 +21,7 @@ import { ThemeDefinition } from "@notesnook/theme"; export type ClipArea = "full-page" | "visible" | "selection" | "article"; -export type ClipMode = "simplified" | "screenshot" | "complete"; +export type ClipMode = "bookmark" | "simplified" | "screenshot" | "complete"; export type User = { email?: string; diff --git a/extensions/web-clipper/src/components/icons/index.ts b/extensions/web-clipper/src/components/icons/index.ts index ee1f97e76..bba876573 100644 --- a/extensions/web-clipper/src/components/icons/index.ts +++ b/extensions/web-clipper/src/components/icons/index.ts @@ -57,6 +57,7 @@ export const Icons = { visible: mdiViewDayOutline, selection: mdiCursorDefaultClickOutline, + bookmark: mdiBookmarkOutline, simplified: mdiTextBoxOutline, screenshot: mdiFitToScreenOutline, complete: mdiViewDashboardOutline, diff --git a/extensions/web-clipper/src/views/main.tsx b/extensions/web-clipper/src/views/main.tsx index 80b0de2a3..8f99a1d32 100644 --- a/extensions/web-clipper/src/views/main.tsx +++ b/extensions/web-clipper/src/views/main.tsx @@ -68,6 +68,11 @@ const clipAreas: { name: string; id: ClipArea; icon: string }[] = [ const clipModes: { name: string; id: ClipMode; icon: string; pro?: boolean }[] = [ + { + name: "Bookmark", + id: "bookmark", + icon: Icons.bookmark + }, { name: "Simplified", id: "simplified", @@ -166,7 +171,7 @@ export function Main() { }, [settings]); async function startClip() { - if (!clipArea || !clipMode) return; + if (!clipArea || !clipMode || clipMode === "bookmark") return; try { setError(undefined); @@ -268,7 +273,11 @@ export function Main() { setClipperState(ClipperState.Idle); setClipArea(item.id); }} - disabled={isClipping || clipperState === ClipperState.Clipped} + disabled={ + isClipping || + clipperState === ClipperState.Clipped || + clipMode === "bookmark" + } sx={{ display: "flex", borderRadius: "default", @@ -342,55 +351,58 @@ export function Main() { ))} - {clipData && clipData.data && !isClipping && ( - - { - const winUrl = URL.createObjectURL( - new Blob(["\ufeff", clipData.data], { type: "text/html" }) - ); - await browser.windows.create({ - url: winUrl - }); - }} - > - Clip done. Click here to preview. - - { - setClipData(undefined); - setClipperState(ClipperState.Idle); - }} - > - Discard - - - )} + {clipMode !== "bookmark" && + clipData && + clipData.data && + !isClipping && ( + + { + const winUrl = URL.createObjectURL( + new Blob(["\ufeff", clipData.data], { type: "text/html" }) + ); + await browser.windows.create({ + url: winUrl + }); + }} + > + Clip done. Click here to preview. + + { + setClipData(undefined); + setClipperState(ClipperState.Idle); + }} + > + Discard + + + )} {error && ( { if ( - clipperState === ClipperState.Idle || - clipperState === ClipperState.Error + clipMode !== "bookmark" && + (clipperState === ClipperState.Idle || + clipperState === ClipperState.Error) ) { await startClip(); return; } - if (!clipData || !title || !clipArea || !clipMode || !url) return; + if (!title || !clipArea || !clipMode || !url) return; + + const data = + clipMode === "bookmark" + ? { + data: createBookmark(url, title) + } + : clipData; + + if (!data) return; const notesnook = await connectApi(false); if (!notesnook) { @@ -476,7 +498,7 @@ export function Main() { note, refs, pageTitle: pageTitle.current, - ...clipData + ...data }); setClipData(undefined); @@ -492,7 +514,9 @@ export function Main() { window.close(); }} > - {clipperButtonLabelMap[clipperState]} + {clipMode === "bookmark" + ? "Save bookmark" + : clipperButtonLabelMap[clipperState]}