Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
86fa187a45
|
|
@ -29,6 +29,7 @@
|
|||
"@codemirror/commands": "6.2.2",
|
||||
"@codemirror/lang-markdown": "6.1.1",
|
||||
"@codemirror/language": "6.6.0",
|
||||
"@codemirror/language-data": "6.2.1",
|
||||
"@codemirror/state": "6.2.0",
|
||||
"@codemirror/theme-one-dark": "6.1.1",
|
||||
"@codemirror/view": "6.9.4",
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
"@headlessui/react": "1.7.14",
|
||||
"@heroicons/react": "2.0.17",
|
||||
"@iconify-json/mingcute": "^1.1.5",
|
||||
"@lezer/highlight": "*",
|
||||
"@mantine/core": "^6.0.7",
|
||||
"@monaco-editor/react": "4.5.0",
|
||||
"@popperjs/core": "^2.11.7",
|
||||
|
|
@ -54,7 +56,6 @@
|
|||
"@tanstack/react-query-devtools": "4.29.3",
|
||||
"@tanstack/react-query-persist-client": "4.29.3",
|
||||
"@uiw/codemirror-extensions-events": "4.19.16",
|
||||
"@uiw/react-codemirror": "4.19.16",
|
||||
"@urql/core": "4.0.4",
|
||||
"aplayer": "^1.10.1",
|
||||
"aplayer-react": "^1.0.5",
|
||||
|
|
|
|||
1260
pnpm-lock.yaml
1260
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -23,7 +23,7 @@ import { Logo } from "~/components/common/Logo"
|
|||
import { getStorage } from "~/lib/storage"
|
||||
import { useGetPagesBySite } from "~/queries/page"
|
||||
import { DashboardTopbar } from "./DashboardTopbar"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { useIsMobileLayout } from "~/hooks/useMobileLayout"
|
||||
|
||||
export function DashboardLayout({
|
||||
children,
|
||||
|
|
@ -47,7 +47,7 @@ export function DashboardLayout({
|
|||
const [hasPermission, setHasPermission] = React.useState(false)
|
||||
const { t } = useTranslation("dashboard")
|
||||
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const isMobileLayout = useIsMobileLayout()
|
||||
|
||||
useEffect(() => {
|
||||
if (ssrReady) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { cn } from "~/lib/utils"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { useIsMobileLayout } from "~/hooks/useMobileLayout"
|
||||
|
||||
export const DashboardMain: React.FC<{
|
||||
children: React.ReactNode
|
||||
|
|
@ -9,7 +9,7 @@ export const DashboardMain: React.FC<{
|
|||
className?: string
|
||||
}> = ({ children, fullWidth, title, className }) => {
|
||||
const { t } = useTranslation("dashboard")
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const isMobileLayout = useIsMobileLayout()
|
||||
|
||||
return (
|
||||
<div className="flex-1">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,323 @@
|
|||
import type { EditorState } from "@codemirror/state"
|
||||
import { Annotation } from "@codemirror/state"
|
||||
|
||||
import { HighlightStyle } from "@codemirror/language"
|
||||
import { EditorView, KeyBinding, ViewUpdate } from "@codemirror/view"
|
||||
import { tags } from "@lezer/highlight"
|
||||
import type { Tag } from "@lezer/highlight"
|
||||
import {
|
||||
Suspense,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import {
|
||||
useCodeMirrorAutoToggleTheme,
|
||||
useCodeMirrorStyle,
|
||||
} from "~/hooks/useCodemirrorTheme"
|
||||
import { useIsDark } from "~/hooks/useDarkMode"
|
||||
import { useGetState } from "~/hooks/useGetState"
|
||||
import { useIsUnmounted } from "~/hooks/useLifecycle"
|
||||
import { useIsMobileLayout } from "~/hooks/useMobileLayout"
|
||||
|
||||
const LoadingHolder = () => {
|
||||
const { t } = useTranslation("common")
|
||||
return (
|
||||
<div className="flex-1 h-12 flex items-center justify-center">
|
||||
{t("Loading")}...
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface XLogCodeMirrorEditorProps {
|
||||
value: string
|
||||
onChange?: (value: string, viewUpdate: ViewUpdate) => void
|
||||
handleDropFile?: (file: File) => void
|
||||
onScroll?: (scrollTop: number) => void
|
||||
onUpdate?: (update: ViewUpdate) => void
|
||||
onCreateEditor?: (view: EditorView, state: EditorState) => void
|
||||
onMouseEnter?: () => void
|
||||
}
|
||||
|
||||
export const CodeMirrorEditor = forwardRef<
|
||||
EditorView | null,
|
||||
XLogCodeMirrorEditorProps
|
||||
>((props, ref) => {
|
||||
return (
|
||||
<Suspense fallback={<LoadingHolder />}>
|
||||
<LazyCodeMirrorEditor {...props} ref={ref} />
|
||||
</Suspense>
|
||||
)
|
||||
})
|
||||
CodeMirrorEditor.displayName = "CodeMirrorEditor"
|
||||
|
||||
const External = Annotation.define<boolean>()
|
||||
|
||||
const LazyCodeMirrorEditor = forwardRef<
|
||||
EditorView | null,
|
||||
XLogCodeMirrorEditorProps
|
||||
>((props, ref) => {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const editorElementRef = useRef<HTMLDivElement>(null)
|
||||
const isUnmounted = useIsUnmounted()
|
||||
const { t } = useTranslation("dashboard")
|
||||
const isMobileLayout = useIsMobileLayout()
|
||||
|
||||
const [cmEditor, setCmEditor] = useState<EditorView | null>(null)
|
||||
const isDark = useIsDark()
|
||||
|
||||
useCodeMirrorStyle(cmEditor)
|
||||
useCodeMirrorAutoToggleTheme(cmEditor, isDark)
|
||||
|
||||
useImperativeHandle(ref, () => cmEditor!)
|
||||
|
||||
const { value, handleDropFile, onScroll, onMouseEnter } = props
|
||||
|
||||
const getHandleDropFile = useGetState(handleDropFile)
|
||||
const getOnScroll = useGetState(onScroll)
|
||||
const getValue = useGetState(value)
|
||||
const getProps = useGetState(props)
|
||||
|
||||
useEffect(() => {
|
||||
if (!cmEditor) return
|
||||
if (value === undefined) {
|
||||
return
|
||||
}
|
||||
const currentValue = cmEditor ? cmEditor.state.doc.toString() : ""
|
||||
if (cmEditor && value !== currentValue) {
|
||||
cmEditor.dispatch({
|
||||
changes: { from: 0, to: currentValue.length, insert: value || "" },
|
||||
annotations: [External.of(true)],
|
||||
})
|
||||
}
|
||||
}, [value, cmEditor])
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([
|
||||
import("@codemirror/state"),
|
||||
import("@codemirror/view"),
|
||||
import("@codemirror/lang-markdown"),
|
||||
import("@uiw/codemirror-extensions-events"),
|
||||
import("~/hooks/useCodemirrorTheme"),
|
||||
import("@codemirror/language"),
|
||||
import("@codemirror/commands"),
|
||||
import("@codemirror/language-data"),
|
||||
]).then((modules) => {
|
||||
if (isUnmounted()) return
|
||||
if (!editorElementRef.current) return
|
||||
const [
|
||||
// @codemirror/state
|
||||
{ EditorState },
|
||||
// @codemirror/view
|
||||
{
|
||||
EditorView,
|
||||
dropCursor,
|
||||
drawSelection,
|
||||
crosshairCursor,
|
||||
keymap,
|
||||
placeholder,
|
||||
},
|
||||
// @codemirror/lang-markdown
|
||||
{ markdown, markdownKeymap, markdownLanguage },
|
||||
// @uiw/codemirror-extensions-events
|
||||
{ scroll },
|
||||
{ codemirrorReconfigureExtension },
|
||||
// @codemirror/language
|
||||
{ syntaxHighlighting, indentOnInput },
|
||||
// @codemirror/commands
|
||||
{ defaultKeymap, history, historyKeymap, indentWithTab },
|
||||
// @codemirror/language-data
|
||||
{ languages },
|
||||
] = modules
|
||||
|
||||
const editorState = EditorState.create({
|
||||
doc: getValue(),
|
||||
|
||||
extensions: [
|
||||
placeholder(t("Start writing...") || ""),
|
||||
EditorView.updateListener.of((vu) => {
|
||||
const props = getProps()
|
||||
const { onUpdate, onChange } = props
|
||||
onUpdate?.(vu)
|
||||
|
||||
if (
|
||||
vu.docChanged &&
|
||||
typeof onChange === "function" &&
|
||||
// Fix echoing of the remote changes:
|
||||
// If transaction is market as remote we don't have to call `onChange` handler again
|
||||
!vu.transactions.some((tr) => tr.annotation(External))
|
||||
) {
|
||||
const doc = vu.state.doc
|
||||
const value = doc.toString()
|
||||
onChange(value, vu)
|
||||
}
|
||||
}),
|
||||
|
||||
indentOnInput(),
|
||||
drawSelection(),
|
||||
dropCursor(),
|
||||
crosshairCursor(),
|
||||
history(),
|
||||
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
|
||||
[EditorView.theme({}), syntaxHighlighting(codeMirrorMarkdownSyntax)],
|
||||
...codemirrorReconfigureExtension,
|
||||
|
||||
markdown({
|
||||
base: markdownLanguage,
|
||||
codeLanguages: languages,
|
||||
}),
|
||||
|
||||
keymap.of([
|
||||
...defaultKeymap,
|
||||
...historyKeymap,
|
||||
...markdownKeymap,
|
||||
indentWithTab,
|
||||
] as KeyBinding[]),
|
||||
|
||||
EditorView.domEventHandlers({
|
||||
drop(e) {
|
||||
const items = Array.from(e.dataTransfer?.items || [])
|
||||
{
|
||||
;(async () => {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const file = items[i]?.getAsFile()
|
||||
if (file) {
|
||||
getHandleDropFile()?.(file)
|
||||
}
|
||||
}
|
||||
})()
|
||||
}
|
||||
},
|
||||
paste(e) {
|
||||
const files = e.clipboardData?.files
|
||||
if (files) {
|
||||
const items = Array.from(files)
|
||||
{
|
||||
;(async () => {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
getHandleDropFile()?.(items[i])
|
||||
}
|
||||
})()
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
scroll({
|
||||
scroll: (evn) => {
|
||||
getOnScroll()?.((evn.target as any)?.scrollTop)
|
||||
},
|
||||
}),
|
||||
EditorView.lineWrapping,
|
||||
],
|
||||
})
|
||||
|
||||
const view = new EditorView({
|
||||
state: editorState,
|
||||
parent: editorElementRef.current,
|
||||
})
|
||||
|
||||
getProps().onCreateEditor?.(view, editorState)
|
||||
setCmEditor(view)
|
||||
setLoading(false)
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => () => cmEditor?.destroy(), [cmEditor])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={editorElementRef}
|
||||
onMouseEnter={onMouseEnter}
|
||||
className={
|
||||
loading
|
||||
? ""
|
||||
: `h-full ${isMobileLayout ? "w-full" : "border-r w-1/2 px-5"}`
|
||||
}
|
||||
/>
|
||||
{loading && <LoadingHolder />}
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
LazyCodeMirrorEditor.displayName = "LazyCodeMirrorEditor"
|
||||
|
||||
const monoSpaceTags: Tag[] = [
|
||||
tags.bracket,
|
||||
tags.angleBracket,
|
||||
tags.squareBracket,
|
||||
tags.paren,
|
||||
tags.brace,
|
||||
tags.float,
|
||||
tags.monospace,
|
||||
tags.keyword,
|
||||
tags.character,
|
||||
tags.propertyName,
|
||||
tags.macroName,
|
||||
tags.function(tags.variableName),
|
||||
tags.labelName,
|
||||
tags.definition(tags.name),
|
||||
tags.typeName,
|
||||
tags.annotation,
|
||||
tags.modifier,
|
||||
tags.self,
|
||||
tags.namespace,
|
||||
tags.comment,
|
||||
tags.bool,
|
||||
/*@__PURE__*/ tags.special(tags.variableName),
|
||||
tags.className,
|
||||
tags.number,
|
||||
tags.changed,
|
||||
tags.operator,
|
||||
tags.operatorKeyword,
|
||||
tags.escape,
|
||||
tags.regexp,
|
||||
/*@__PURE__*/ tags.special(tags.string),
|
||||
tags.name,
|
||||
tags.deleted,
|
||||
tags.character,
|
||||
]
|
||||
const codeMirrorMarkdownSyntax = HighlightStyle.define([
|
||||
{
|
||||
tag: tags.heading1,
|
||||
fontSize: "1.4em",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: tags.heading2,
|
||||
fontSize: "1.3em",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: tags.heading3,
|
||||
fontSize: "1.2em",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: tags.heading4,
|
||||
fontSize: "1.1em",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: tags.heading5,
|
||||
fontSize: "1.1em",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{
|
||||
tag: tags.heading6,
|
||||
fontSize: "1.1em",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
{ tag: tags.strong, fontWeight: "bold" },
|
||||
{ tag: tags.emphasis, fontStyle: "italic" },
|
||||
{ tag: tags.deleted, textDecoration: "line-through" },
|
||||
...monoSpaceTags.map((tag) => ({
|
||||
tag,
|
||||
fontFamily: `"OperatorMonoSSmLig Nerd Font","Cascadia Code PL","FantasqueSansMono Nerd Font","operator mono","Fira code Retina","Fira code","Consolas", Monaco, "Hannotate SC", monospace, -apple-system`,
|
||||
})),
|
||||
])
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
import CodeMirror from "@uiw/react-codemirror"
|
||||
import { EditorView, ViewUpdate } from "@codemirror/view"
|
||||
import { markdown } from "@codemirror/lang-markdown"
|
||||
import { scroll } from "@uiw/codemirror-extensions-events"
|
||||
import type { EditorState } from "@codemirror/state"
|
||||
import { useState, useEffect, useMemo } from "react"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import {
|
||||
codemirrorReconfigureExtension,
|
||||
useCodeMirrorAutoToggleTheme,
|
||||
} from "~/hooks/useCodemirrorTheme"
|
||||
import { useIsDark } from "~/hooks/useDarkMode"
|
||||
|
||||
export const Editor: React.FC<{
|
||||
value: string
|
||||
onChange?: (value: string, viewUpdate: ViewUpdate) => void
|
||||
handleDropFile?: (file: File) => void
|
||||
onScroll?: (scrollTop: number) => void
|
||||
onUpdate?: (update: ViewUpdate) => void
|
||||
onCreateEditor?: (view: EditorView, state: EditorState) => void
|
||||
onMouseEnter?: () => void
|
||||
}> = ({
|
||||
value,
|
||||
onChange,
|
||||
handleDropFile,
|
||||
onScroll,
|
||||
onUpdate,
|
||||
onCreateEditor,
|
||||
onMouseEnter,
|
||||
}) => {
|
||||
const { t } = useTranslation("dashboard")
|
||||
const [extensions, setExtensions] = useState<any>([])
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const [editor, setCmEditor] = useState<EditorView | null>(null)
|
||||
const isDark = useIsDark()
|
||||
useCodeMirrorAutoToggleTheme(editor, isDark)
|
||||
|
||||
useEffect(() => {
|
||||
setExtensions([
|
||||
markdown(),
|
||||
EditorView.theme({
|
||||
".cm-scroller": {
|
||||
fontFamily: "var(--font-sans)",
|
||||
fontSize: "1rem",
|
||||
overflow: "auto",
|
||||
height: "100%",
|
||||
padding: isMobileLayout ? "0 1.25rem" : "unset",
|
||||
},
|
||||
".cm-content": {
|
||||
paddingBottom: "600px",
|
||||
},
|
||||
"&.cm-editor.cm-focused": {
|
||||
outline: "none",
|
||||
},
|
||||
"&.cm-editor": {
|
||||
height: "100%",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
}),
|
||||
EditorView.domEventHandlers({
|
||||
drop(e) {
|
||||
const items = Array.from(e.dataTransfer?.items || [])
|
||||
{
|
||||
;(async () => {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const file = items[i]?.getAsFile()
|
||||
if (file) {
|
||||
handleDropFile?.(file)
|
||||
}
|
||||
}
|
||||
})()
|
||||
}
|
||||
},
|
||||
paste(e) {
|
||||
const files = e.clipboardData?.files
|
||||
if (files) {
|
||||
const items = Array.from(files)
|
||||
{
|
||||
;(async () => {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
handleDropFile?.(items[i])
|
||||
}
|
||||
})()
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
scroll({
|
||||
scroll: (evn) => {
|
||||
onScroll?.((evn.target as any)?.scrollTop)
|
||||
},
|
||||
}),
|
||||
EditorView.lineWrapping,
|
||||
...codemirrorReconfigureExtension,
|
||||
])
|
||||
}, [onScroll, handleDropFile])
|
||||
|
||||
return useMemo(
|
||||
() => (
|
||||
<CodeMirror
|
||||
className={`h-full ${
|
||||
isMobileLayout ? "w-full" : "border-r w-1/2 px-5"
|
||||
}`}
|
||||
value={value}
|
||||
extensions={extensions}
|
||||
onCreateEditor={(view, state) => {
|
||||
setCmEditor(view)
|
||||
onCreateEditor?.(view, state)
|
||||
}}
|
||||
basicSetup={{
|
||||
lineNumbers: false,
|
||||
foldGutter: false,
|
||||
highlightActiveLine: false,
|
||||
history: true,
|
||||
defaultKeymap: true,
|
||||
historyKeymap: true,
|
||||
dropCursor: true,
|
||||
drawSelection: true,
|
||||
indentOnInput: true,
|
||||
crosshairCursor: true,
|
||||
allowMultipleSelections: true,
|
||||
syntaxHighlighting: true,
|
||||
}}
|
||||
indentWithTab={true}
|
||||
onChange={onChange}
|
||||
placeholder={t("Start writing...") || ""}
|
||||
onUpdate={onUpdate}
|
||||
onMouseEnter={onMouseEnter}
|
||||
/>
|
||||
),
|
||||
[value, onChange, extensions, onUpdate, onCreateEditor, onMouseEnter],
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useEffect } from "react"
|
||||
import { default as NextImage, ImageProps } from "next/image"
|
||||
import { toGateway, toIPFS } from "~/lib/ipfs-parser"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { useIsMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { useGetState } from "~/hooks/useGetState"
|
||||
|
||||
type TImageProps = {
|
||||
|
|
@ -32,7 +32,7 @@ export const Image: React.FC<TImageProps> = ({
|
|||
const noOptimization = className?.includes("no-optimization")
|
||||
const imageRefInternal = React.useRef<HTMLImageElement>(null)
|
||||
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const isMobileLayout = useIsMobileLayout()
|
||||
const getSrc = useGetState(src)
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
import type { Extension } from "@codemirror/state"
|
||||
import { Compartment } from "@codemirror/state"
|
||||
import { EditorView } from "@codemirror/view"
|
||||
import { useEffect } from "react"
|
||||
import { useEffect, useRef } from "react"
|
||||
|
||||
import { oneDark } from "@codemirror/theme-one-dark"
|
||||
import { githubLight } from "@ddietr/codemirror-themes/theme/github-light"
|
||||
import { useIsUnmounted } from "./useLifecycle"
|
||||
import { useIsMobileLayout } from "./useMobileLayout"
|
||||
|
||||
const extensionMap = {
|
||||
theme: new Compartment(),
|
||||
style: new Compartment(),
|
||||
}
|
||||
|
||||
export const codemirrorReconfigureExtension: Extension[] = [
|
||||
extensionMap.theme.of([]),
|
||||
extensionMap.style.of([]),
|
||||
]
|
||||
|
||||
export const useCodeMirrorAutoToggleTheme = (
|
||||
|
|
@ -31,3 +35,49 @@ export const useCodeMirrorAutoToggleTheme = (
|
|||
}
|
||||
}, [view, isDark])
|
||||
}
|
||||
|
||||
export const useCodeMirrorStyle = (view: EditorView | null) => {
|
||||
const isMobileLayout = useIsMobileLayout()
|
||||
const isUnmounted = useIsUnmounted()
|
||||
const once = useRef(false)
|
||||
const getStyle = () => {
|
||||
return {
|
||||
".cm-scroller": {
|
||||
fontFamily: "var(--font-sans)",
|
||||
fontSize: "1rem",
|
||||
overflow: "auto",
|
||||
height: "100%",
|
||||
padding: isMobileLayout ? "0 1.25rem" : "unset",
|
||||
},
|
||||
".cm-content": {
|
||||
paddingBottom: "600px",
|
||||
},
|
||||
"&.cm-editor.cm-focused": {
|
||||
outline: "none",
|
||||
},
|
||||
"&.cm-editor": {
|
||||
height: "100%",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
".cm-s-markdown .cm-string": {
|
||||
fontFamily: '"Fira Code", monospace',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!view) return
|
||||
view.dispatch({
|
||||
effects: [extensionMap.style.reconfigure(EditorView.theme(getStyle()))],
|
||||
})
|
||||
}, [view, isMobileLayout])
|
||||
|
||||
if (isUnmounted()) return
|
||||
if (!once.current) {
|
||||
if (!view) return
|
||||
view.dispatch({
|
||||
effects: [extensionMap.style.reconfigure(EditorView.theme(getStyle()))],
|
||||
})
|
||||
once.current = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect, useRef } from "react"
|
||||
|
||||
export const useGetState = (state: any) => {
|
||||
export const useGetState = <T>(state: T): (() => T) => {
|
||||
const ref = useRef(state)
|
||||
|
||||
useEffect(() => void (ref.current = state), [state])
|
||||
|
|
|
|||
|
|
@ -1,24 +1,31 @@
|
|||
import { useCallback, useEffect, useState } from "react"
|
||||
import { useCallback, useEffect } from "react"
|
||||
import { create } from "zustand"
|
||||
|
||||
const mobileWidth = 1024
|
||||
|
||||
const useLayoutStore = create<{
|
||||
isMobile: boolean | undefined
|
||||
}>(() => ({
|
||||
isMobile: undefined,
|
||||
}))
|
||||
|
||||
export function useMobileLayout() {
|
||||
const [isMobile, setIsMobile] = useState<boolean>()
|
||||
|
||||
const onResize = useCallback(() => {
|
||||
setIsMobile(window.innerWidth < mobileWidth)
|
||||
const calc = useCallback(() => {
|
||||
useLayoutStore.setState({
|
||||
isMobile: window.innerWidth < mobileWidth,
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("resize", onResize)
|
||||
window.addEventListener("resize", calc)
|
||||
return () => {
|
||||
window.removeEventListener("resize", onResize)
|
||||
window.removeEventListener("resize", calc)
|
||||
}
|
||||
}, [onResize])
|
||||
}, [calc])
|
||||
|
||||
useEffect(() => {
|
||||
setIsMobile(window.innerWidth < mobileWidth)
|
||||
calc()
|
||||
}, [])
|
||||
|
||||
return isMobile
|
||||
}
|
||||
|
||||
export const useIsMobileLayout = () => useLayoutStore((state) => state.isMobile)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import { createIDBPersister } from "~/lib/persister.client"
|
|||
import { urlComposer } from "~/lib/url-composer"
|
||||
import { AppPropsWithLayout } from "types/next"
|
||||
import { useDarkMode } from "~/hooks/useDarkMode"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
|
||||
Network.setIpfsGateway(IPFS_GATEWAY)
|
||||
|
||||
|
|
@ -40,6 +41,8 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
|||
const getLayout = Component.getLayout ?? ((page) => page)
|
||||
|
||||
useDarkMode()
|
||||
useMobileLayout()
|
||||
|
||||
return (
|
||||
<WagmiConfig client={wagmiClient}>
|
||||
<PersistQueryClientProvider
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import { useQueryClient } from "@tanstack/react-query"
|
|||
import { PageContent } from "~/components/common/PageContent"
|
||||
import type { Root } from "hast"
|
||||
import type { EditorView } from "@codemirror/view"
|
||||
import { Editor } from "~/components/ui/Editor"
|
||||
|
||||
import { renderPageContent } from "~/markdown"
|
||||
import { Button } from "~/components/ui/Button"
|
||||
import { Modal } from "~/components/ui/Modal"
|
||||
|
|
@ -42,9 +42,10 @@ import { getServerSideProps as getLayoutServerSideProps } from "~/components/das
|
|||
import { GetServerSideProps } from "next"
|
||||
import { serverSidePropsHandler } from "~/lib/server-side-props"
|
||||
import { getDefaultSlug } from "~/lib/default-slug"
|
||||
import { useMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { useIsMobileLayout } from "~/hooks/useMobileLayout"
|
||||
import { OptionsButton } from "~/components/dashboard/OptionsButton"
|
||||
import NodeID3 from "node-id3"
|
||||
import { CodeMirrorEditor } from "~/components/ui/CodeMirror"
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = serverSidePropsHandler(
|
||||
async (ctx) => {
|
||||
|
|
@ -167,7 +168,7 @@ export default function SubdomainEditor() {
|
|||
|
||||
const createOrUpdatePage = useCreateOrUpdatePage()
|
||||
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const isMobileLayout = useIsMobileLayout()
|
||||
const [isRendering, setIsRendering] = useState(false)
|
||||
|
||||
const savePage = async (published: boolean) => {
|
||||
|
|
@ -682,7 +683,7 @@ export default function SubdomainEditor() {
|
|||
<div className="mt-5 flex-1 flex overflow-hidden">
|
||||
{isMobileLayout ? (
|
||||
!isRendering ? (
|
||||
<Editor
|
||||
<CodeMirrorEditor
|
||||
value={values.content}
|
||||
onChange={onChange}
|
||||
handleDropFile={handleDropFile}
|
||||
|
|
@ -708,7 +709,7 @@ export default function SubdomainEditor() {
|
|||
)
|
||||
) : (
|
||||
<>
|
||||
<Editor
|
||||
<CodeMirrorEditor
|
||||
value={initialContent}
|
||||
onChange={onChange}
|
||||
handleDropFile={handleDropFile}
|
||||
|
|
|
|||
Loading…
Reference in New Issue