mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
Merge pull request #7294 from 01zulfi/webclipper/bookmark
webclipper: add bookmark option
This commit is contained in:
@@ -73,7 +73,11 @@ export class WebExtensionServer implements Server {
|
|||||||
async saveClip(clip: Clip) {
|
async saveClip(clip: Clip) {
|
||||||
let clipContent = "";
|
let clipContent = "";
|
||||||
|
|
||||||
if (clip.mode === "simplified" || clip.mode === "screenshot") {
|
if (
|
||||||
|
clip.mode === "simplified" ||
|
||||||
|
clip.mode === "screenshot" ||
|
||||||
|
clip.mode === "bookmark"
|
||||||
|
) {
|
||||||
clipContent += clip.data;
|
clipContent += clip.data;
|
||||||
} else {
|
} else {
|
||||||
const clippedFile = new File(
|
const clippedFile = new File(
|
||||||
@@ -105,11 +109,17 @@ export class WebExtensionServer implements Server {
|
|||||||
if (isCipher(content)) return;
|
if (isCipher(content)) return;
|
||||||
|
|
||||||
content += clipContent;
|
content += clipContent;
|
||||||
content += h("div", [
|
content +=
|
||||||
h("hr"),
|
clip.mode === "bookmark"
|
||||||
h("p", ["Clipped from ", h("a", [clip.title], { href: clip.url })]),
|
? h("div", [
|
||||||
h("p", [`Date clipped: ${getFormattedDate(Date.now())}`])
|
h("p", [`Date bookmarked: ${getFormattedDate(Date.now())}`]),
|
||||||
]).innerHTML;
|
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({
|
const id = await db.notes.add({
|
||||||
id: note?.id,
|
id: note?.id,
|
||||||
|
|||||||
@@ -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.
|
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
|
||||||
|
|
||||||
`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.
|
`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.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { ThemeDefinition } from "@notesnook/theme";
|
|||||||
|
|
||||||
export type ClipArea = "full-page" | "visible" | "selection" | "article";
|
export type ClipArea = "full-page" | "visible" | "selection" | "article";
|
||||||
|
|
||||||
export type ClipMode = "simplified" | "screenshot" | "complete";
|
export type ClipMode = "bookmark" | "simplified" | "screenshot" | "complete";
|
||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
email?: string;
|
email?: string;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export const Icons = {
|
|||||||
visible: mdiViewDayOutline,
|
visible: mdiViewDayOutline,
|
||||||
selection: mdiCursorDefaultClickOutline,
|
selection: mdiCursorDefaultClickOutline,
|
||||||
|
|
||||||
|
bookmark: mdiBookmarkOutline,
|
||||||
simplified: mdiTextBoxOutline,
|
simplified: mdiTextBoxOutline,
|
||||||
screenshot: mdiFitToScreenOutline,
|
screenshot: mdiFitToScreenOutline,
|
||||||
complete: mdiViewDashboardOutline,
|
complete: mdiViewDashboardOutline,
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ const clipAreas: { name: string; id: ClipArea; icon: string }[] = [
|
|||||||
|
|
||||||
const clipModes: { name: string; id: ClipMode; icon: string; pro?: boolean }[] =
|
const clipModes: { name: string; id: ClipMode; icon: string; pro?: boolean }[] =
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
name: "Bookmark",
|
||||||
|
id: "bookmark",
|
||||||
|
icon: Icons.bookmark
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Simplified",
|
name: "Simplified",
|
||||||
id: "simplified",
|
id: "simplified",
|
||||||
@@ -166,7 +171,7 @@ export function Main() {
|
|||||||
}, [settings]);
|
}, [settings]);
|
||||||
|
|
||||||
async function startClip() {
|
async function startClip() {
|
||||||
if (!clipArea || !clipMode) return;
|
if (!clipArea || !clipMode || clipMode === "bookmark") return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
@@ -268,7 +273,11 @@ export function Main() {
|
|||||||
setClipperState(ClipperState.Idle);
|
setClipperState(ClipperState.Idle);
|
||||||
setClipArea(item.id);
|
setClipArea(item.id);
|
||||||
}}
|
}}
|
||||||
disabled={isClipping || clipperState === ClipperState.Clipped}
|
disabled={
|
||||||
|
isClipping ||
|
||||||
|
clipperState === ClipperState.Clipped ||
|
||||||
|
clipMode === "bookmark"
|
||||||
|
}
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
borderRadius: "default",
|
borderRadius: "default",
|
||||||
@@ -342,55 +351,58 @@ export function Main() {
|
|||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{clipData && clipData.data && !isClipping && (
|
{clipMode !== "bookmark" &&
|
||||||
<Flex sx={{ gap: 1, justifyContent: "space-between" }}>
|
clipData &&
|
||||||
<Text
|
clipData.data &&
|
||||||
variant="body"
|
!isClipping && (
|
||||||
sx={{
|
<Flex sx={{ gap: 1, justifyContent: "space-between" }}>
|
||||||
flex: 1,
|
<Text
|
||||||
mt: 1,
|
variant="body"
|
||||||
bg: "shade",
|
sx={{
|
||||||
color: "accent",
|
flex: 1,
|
||||||
p: 1,
|
mt: 1,
|
||||||
border: "1px solid var(--accent)",
|
bg: "shade",
|
||||||
borderRadius: "default",
|
color: "accent",
|
||||||
cursor: "pointer",
|
p: 1,
|
||||||
":hover": {
|
border: "1px solid var(--accent)",
|
||||||
filter: "brightness(80%)"
|
borderRadius: "default",
|
||||||
}
|
cursor: "pointer",
|
||||||
}}
|
":hover": {
|
||||||
onClick={async () => {
|
filter: "brightness(80%)"
|
||||||
const winUrl = URL.createObjectURL(
|
}
|
||||||
new Blob(["\ufeff", clipData.data], { type: "text/html" })
|
}}
|
||||||
);
|
onClick={async () => {
|
||||||
await browser.windows.create({
|
const winUrl = URL.createObjectURL(
|
||||||
url: winUrl
|
new Blob(["\ufeff", clipData.data], { type: "text/html" })
|
||||||
});
|
);
|
||||||
}}
|
await browser.windows.create({
|
||||||
>
|
url: winUrl
|
||||||
Clip done. Click here to preview.
|
});
|
||||||
</Text>
|
}}
|
||||||
<Text
|
>
|
||||||
variant="body"
|
Clip done. Click here to preview.
|
||||||
sx={{
|
</Text>
|
||||||
mt: 1,
|
<Text
|
||||||
bg: "background-secondary",
|
variant="body"
|
||||||
p: 1,
|
sx={{
|
||||||
borderRadius: "default",
|
mt: 1,
|
||||||
cursor: "pointer",
|
bg: "background-secondary",
|
||||||
":hover": {
|
p: 1,
|
||||||
filter: "brightness(80%)"
|
borderRadius: "default",
|
||||||
}
|
cursor: "pointer",
|
||||||
}}
|
":hover": {
|
||||||
onClick={async () => {
|
filter: "brightness(80%)"
|
||||||
setClipData(undefined);
|
}
|
||||||
setClipperState(ClipperState.Idle);
|
}}
|
||||||
}}
|
onClick={async () => {
|
||||||
>
|
setClipData(undefined);
|
||||||
Discard
|
setClipperState(ClipperState.Idle);
|
||||||
</Text>
|
}}
|
||||||
</Flex>
|
>
|
||||||
)}
|
Discard
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<Text
|
<Text
|
||||||
@@ -454,14 +466,24 @@ export function Main() {
|
|||||||
disabled={isClipping}
|
disabled={isClipping}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (
|
if (
|
||||||
clipperState === ClipperState.Idle ||
|
clipMode !== "bookmark" &&
|
||||||
clipperState === ClipperState.Error
|
(clipperState === ClipperState.Idle ||
|
||||||
|
clipperState === ClipperState.Error)
|
||||||
) {
|
) {
|
||||||
await startClip();
|
await startClip();
|
||||||
return;
|
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);
|
const notesnook = await connectApi(false);
|
||||||
if (!notesnook) {
|
if (!notesnook) {
|
||||||
@@ -476,7 +498,7 @@ export function Main() {
|
|||||||
note,
|
note,
|
||||||
refs,
|
refs,
|
||||||
pageTitle: pageTitle.current,
|
pageTitle: pageTitle.current,
|
||||||
...clipData
|
...data
|
||||||
});
|
});
|
||||||
|
|
||||||
setClipData(undefined);
|
setClipData(undefined);
|
||||||
@@ -492,7 +514,9 @@ export function Main() {
|
|||||||
window.close();
|
window.close();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{clipperButtonLabelMap[clipperState]}
|
{clipMode === "bookmark"
|
||||||
|
? "Save bookmark"
|
||||||
|
: clipperButtonLabelMap[clipperState]}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
@@ -567,3 +591,11 @@ export async function clip(
|
|||||||
settings
|
settings
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBookmark(url: string, title: string) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.setAttribute("href", url);
|
||||||
|
a.setAttribute("title", title);
|
||||||
|
a.innerText = title;
|
||||||
|
return a.outerHTML;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user