Skip to content

Commit

Permalink
Merge branch 'dev' into ssr-meta
Browse files Browse the repository at this point in the history
  • Loading branch information
Innei authored Oct 21, 2024
2 parents 746b3f5 + 4fbe873 commit 5372d52
Show file tree
Hide file tree
Showing 91 changed files with 1,391 additions and 1,167 deletions.
2 changes: 0 additions & 2 deletions apps/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
"msedge-tts": "1.3.4",
"nanoid": "5.0.7",
"ofetch": "1.4.1",
"posthog-js": "1.169.0",
"posthog-node": "4.2.1",
"semver": "7.6.3",
"vscode-languagedetection": "npm:@vscode/vscode-languagedetection@^1.0.22"
},
Expand Down
42 changes: 42 additions & 0 deletions apps/main/src/tipc/app.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import fs from "node:fs"
import fsp from "node:fs/promises"
import path from "node:path"

import { getRendererHandlers } from "@egoist/tipc/main"
Expand Down Expand Up @@ -225,6 +227,46 @@ export const appRoute = {
}),

clearAllData: t.procedure.action(clearAllData),

saveToObsidian: t.procedure
.input<{
url: string
title: string
content: string
author: string
publishedAt: string
vaultPath: string
}>()
.action(async ({ input }) => {
try {
const { url, title, content, author, publishedAt, vaultPath } = input

const fileName = `${(title || publishedAt).trim().slice(0, 20)}.md`
const filePath = path.join(vaultPath, fileName)
const exists = fs.existsSync(filePath)
if (exists) {
return { success: false, error: "File already exists" }
}

const markdown = `---
url: ${url}
author: ${author}
publishedAt: ${publishedAt}
---
# ${title}
${content}
`

await fsp.writeFile(filePath, markdown, "utf-8")
return { success: true }
} catch (error) {
console.error("Failed to save to Obsidian:", error)
const errorMessage = error instanceof Error ? error.message : String(error)
return { success: false, error: errorMessage }
}
}),
}

interface Sender extends Electron.WebContents {
Expand Down
1 change: 0 additions & 1 deletion apps/renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
"nanoid": "5.0.7",
"ofetch": "1.4.1",
"path-to-regexp": "8.2.0",
"posthog-js": "1.169.1",
"re-resizable": "6.10.0",
"react-blurhash": "^0.3.0",
"react-error-boundary": "4.0.13",
Expand Down
8 changes: 8 additions & 0 deletions apps/renderer/src/atoms/server-configs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { atom } from "jotai"

import { createAtomHooks } from "~/lib/jotai"
import type { ServerConfigs } from "~/models"

export const [, , useServerConfigs, , getServerConfigs, setServerConfigs] = createAtomHooks(
atom<Nullable<ServerConfigs>>(null),
)
4 changes: 4 additions & 0 deletions apps/renderer/src/atoms/settings/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export const createDefaultSettings = (): IntegrationSettings => ({
enableOmnivore: false,
omnivoreEndpoint: "",
omnivoreToken: "",

// obsidian
enableObsidian: false,
obsidianVaultPath: "",
})

export const {
Expand Down
1 change: 0 additions & 1 deletion apps/renderer/src/components/icons/users.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { SVGProps } from "react"
import React from "react"

export function PhUsersBold(props: SVGProps<SVGSVGElement>) {
return (
Expand Down
2 changes: 1 addition & 1 deletion apps/renderer/src/components/ui/fab/FABContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { typescriptHappyForwardRef } from "foxact/typescript-happy-forward-ref"
import type { HTMLMotionProps } from "framer-motion"
import { AnimatePresence } from "framer-motion"
import { atom, useAtomValue } from "jotai"
import type React from "react"
import type * as React from "react"
import type { JSX, PropsWithChildren, ReactNode } from "react"
import { useId } from "react"

Expand Down
3 changes: 2 additions & 1 deletion apps/renderer/src/components/ui/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { m, useAnimation } from "framer-motion"
import React, { cloneElement, useEffect } from "react"
import * as React from "react"
import { cloneElement, useEffect } from "react"

import { cn } from "~/lib/utils"

Expand Down
90 changes: 90 additions & 0 deletions apps/renderer/src/components/ui/markdown/HTML.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import katexStyle from "katex/dist/katex.min.css?raw"
import { createElement, Fragment, memo, useEffect, useMemo, useRef, useState } from "react"

import { MemoedDangerousHTMLStyle } from "~/components/common/MemoedDangerousHTMLStyle"
import { parseHtml } from "~/lib/parse-html"
import { useWrappedElementSize } from "~/providers/wrapped-element-provider"

import type { MediaInfoRecord } from "../media"
import { MediaContainerWidthProvider, MediaInfoRecordProvider } from "../media"
import { MarkdownRenderContainerRefContext } from "./context"

export type HTMLProps<A extends keyof JSX.IntrinsicElements = "div"> = {
children: string | null | undefined
as: A

accessory?: React.ReactNode
noMedia?: boolean
mediaInfo?: MediaInfoRecord

handleTranslate?: (html: HTMLElement | null) => void
} & JSX.IntrinsicElements[A] &
Partial<{
renderInlineStyle: boolean
}>
const HTMLImpl = <A extends keyof JSX.IntrinsicElements = "div">(props: HTMLProps<A>) => {
const {
children,
renderInlineStyle,
as = "div",
accessory,
noMedia,
mediaInfo,
handleTranslate: translate,
...rest
} = props
const [remarkOptions, setRemarkOptions] = useState({
renderInlineStyle,
noMedia,
})
const [shouldForceReMountKey, setShouldForceReMountKey] = useState(0)

useEffect(() => {
setRemarkOptions((options) => {
if (JSON.stringify(options) === JSON.stringify({ renderInlineStyle, noMedia })) {
return options
}

setShouldForceReMountKey((key) => key + 1)
return { ...options, renderInlineStyle, noMedia }
})
}, [renderInlineStyle, noMedia])

const [refElement, setRefElement] = useState<HTMLElement | null>(null)

const onceRef = useRef(false)
useEffect(() => {
if (onceRef.current || !refElement) {
return
}

translate?.(refElement)
onceRef.current = true
}, [translate, refElement])

const markdownElement = useMemo(
() =>
children &&
parseHtml(children, {
...remarkOptions,
}).toContent(),
[children, remarkOptions],
)

const { w: containerWidth } = useWrappedElementSize()

if (!markdownElement) return null
return (
<MarkdownRenderContainerRefContext.Provider value={refElement}>
<MediaContainerWidthProvider width={containerWidth}>
<MediaInfoRecordProvider mediaInfo={mediaInfo}>
<MemoedDangerousHTMLStyle>{katexStyle}</MemoedDangerousHTMLStyle>
{createElement(as, { ...rest, ref: setRefElement }, markdownElement)}
</MediaInfoRecordProvider>
</MediaContainerWidthProvider>
{!!accessory && <Fragment key={shouldForceReMountKey}>{accessory}</Fragment>}
</MarkdownRenderContainerRefContext.Provider>
)
}

export const HTML = memo(HTMLImpl)
89 changes: 1 addition & 88 deletions apps/renderer/src/components/ui/markdown/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import katexStyle from "katex/dist/katex.min.css?raw"
import { createElement, Fragment, memo, useEffect, useMemo, useRef, useState } from "react"
import { useMemo, useState } from "react"

import { MemoedDangerousHTMLStyle } from "~/components/common/MemoedDangerousHTMLStyle"
import { parseHtml } from "~/lib/parse-html"
import type { RemarkOptions } from "~/lib/parse-markdown"
import { parseMarkdown } from "~/lib/parse-markdown"
import { cn } from "~/lib/utils"
import { useWrappedElementSize } from "~/providers/wrapped-element-provider"

import type { MediaInfoRecord } from "../media"
import { MediaContainerWidthProvider, MediaInfoRecordProvider } from "../media"
import { MarkdownRenderContainerRefContext } from "./context"

export const Markdown: Component<
Expand Down Expand Up @@ -39,84 +33,3 @@ export const Markdown: Component<
</MarkdownRenderContainerRefContext.Provider>
)
}

const HTMLImpl = <A extends keyof JSX.IntrinsicElements = "div">(
props: {
children: string | null | undefined
as: A

accessory?: React.ReactNode
noMedia?: boolean
mediaInfo?: MediaInfoRecord

translate?: (html: HTMLElement | null) => void
} & JSX.IntrinsicElements[A] &
Partial<{
renderInlineStyle: boolean
}>,
) => {
const {
children,
renderInlineStyle,
as = "div",
accessory,
noMedia,
mediaInfo,
translate,
...rest
} = props
const [remarkOptions, setRemarkOptions] = useState({
renderInlineStyle,
noMedia,
})
const [shouldForceReMountKey, setShouldForceReMountKey] = useState(0)

useEffect(() => {
setRemarkOptions((options) => {
if (JSON.stringify(options) === JSON.stringify({ renderInlineStyle, noMedia })) {
return options
}

setShouldForceReMountKey((key) => key + 1)
return { ...options, renderInlineStyle, noMedia }
})
}, [renderInlineStyle, noMedia])

const [refElement, setRefElement] = useState<HTMLElement | null>(null)

const onceRef = useRef(false)
useEffect(() => {
if (onceRef.current || !refElement) {
return
}

translate?.(refElement)
onceRef.current = true
}, [translate, refElement])

const markdownElement = useMemo(
() =>
children &&
parseHtml(children, {
...remarkOptions,
}).toContent(),
[children, remarkOptions],
)

const { w: containerWidth } = useWrappedElementSize()

if (!markdownElement) return null
return (
<MarkdownRenderContainerRefContext.Provider value={refElement}>
<MediaContainerWidthProvider width={containerWidth}>
<MediaInfoRecordProvider mediaInfo={mediaInfo}>
<MemoedDangerousHTMLStyle>{katexStyle}</MemoedDangerousHTMLStyle>
{createElement(as, { ...rest, ref: setRefElement }, markdownElement)}
</MediaInfoRecordProvider>
</MediaContainerWidthProvider>
{!!accessory && <Fragment key={shouldForceReMountKey}>{accessory}</Fragment>}
</MarkdownRenderContainerRefContext.Provider>
)
}

export const HTML = memo(HTMLImpl)
15 changes: 13 additions & 2 deletions apps/renderer/src/components/ui/markdown/context.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
import { createContext } from "react"
import { createContext as reactCreateContext } from "react"
import { createContext } from "use-context-selector"

export const MarkdownRenderContainerRefContext = createContext<HTMLElement | null>(null)
import type { MarkdownImage, MarkdownRenderActions } from "./types"

export const MarkdownRenderContainerRefContext = reactCreateContext<HTMLElement | null>(null)

export const MarkdownImageRecordContext = createContext<Record<string, MarkdownImage>>({})

export const MarkdownRenderActionContext = reactCreateContext<MarkdownRenderActions>({
transformUrl: (url) => url ?? "",
isAudio: () => false,
ensureAndRenderTimeStamp: () => false,
})
1 change: 0 additions & 1 deletion apps/renderer/src/components/ui/markdown/index.ts

This file was deleted.

17 changes: 10 additions & 7 deletions apps/renderer/src/components/ui/markdown/renderers/BlockImage.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useContext } from "react"
import { useContextSelector } from "use-context-selector"

import { cn } from "~/lib/utils"
import { useEntryContentContext } from "~/modules/entry-content/hooks"
import { useWrappedElementSize } from "~/providers/wrapped-element-provider"
import { useEntry } from "~/store/entry"

import { Media } from "../../media"
import { usePopulatedFullUrl } from "../utils"
import { MarkdownImageRecordContext, MarkdownRenderActionContext } from "../context"

export const MarkdownBlockImage = (
props: React.ImgHTMLAttributes<HTMLImageElement> & {
Expand All @@ -15,17 +16,19 @@ export const MarkdownBlockImage = (
},
) => {
const size = useWrappedElementSize()
const { feedId } = useEntryContentContext()

const src = usePopulatedFullUrl(feedId, props.src)
const { transformUrl } = useContext(MarkdownRenderActionContext)
const src = transformUrl(props.src)

const { entryId } = useEntryContentContext()
const media = useEntry(entryId, (entry) => entry?.entries.media?.find((m) => m.url === props.src))
const media = useContextSelector(MarkdownImageRecordContext, (record) =>
props.src ? record[props.src] : null,
)

return (
<Media
type="photo"
{...props}
loading="lazy"
src={src}
height={media?.height || props.height}
width={media?.width || props.width}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useContext } from "react"

import { cn } from "~/lib/utils"
import { useEntryContentContext } from "~/modules/entry-content/hooks"

import { Media } from "../../media"
import { usePopulatedFullUrl } from "../utils"
import { MarkdownRenderActionContext } from "../context"

export const MarkdownInlineImage = (
props: React.ImgHTMLAttributes<HTMLImageElement> & {
Expand All @@ -12,12 +13,13 @@ export const MarkdownInlineImage = (
}
},
) => {
const { feedId } = useEntryContentContext()
const populatedUrl = usePopulatedFullUrl(feedId, props.src)
const { transformUrl } = useContext(MarkdownRenderActionContext)
const populatedUrl = transformUrl(props.src)
return (
<Media
type="photo"
{...props}
loading="lazy"
src={populatedUrl}
mediaContainerClassName={cn("inline max-w-full rounded-md")}
popper
Expand Down
Loading

0 comments on commit 5372d52

Please sign in to comment.