feat: codemirror theme
Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
2df738dd24
commit
8d63bf8a87
|
|
@ -29,6 +29,7 @@
|
|||
"@codemirror/language": "6.6.0",
|
||||
"@codemirror/state": "6.2.0",
|
||||
"@codemirror/view": "6.9.4",
|
||||
"@codemirror/theme-one-dark": "6.1.1",
|
||||
"@crossbell/connect-kit": "0.0.63",
|
||||
"@crossbell/contract": "0.0.63",
|
||||
"@crossbell/indexer": "0.0.63",
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
"@crossbell/ui": "0.0.63",
|
||||
"@crossbell/util-hooks": "0.0.63",
|
||||
"@dqbd/tiktoken": "^1.0.4",
|
||||
"@ddietr/codemirror-themes": "1.4.0",
|
||||
"@emoji-mart/data": "1.1.2",
|
||||
"@emoji-mart/react": "1.1.1",
|
||||
"@floating-ui/react": "^0.23.0",
|
||||
|
|
@ -116,7 +118,8 @@
|
|||
"unist-util-visit": "4.1.2",
|
||||
"use-onclickoutside": "0.4.1",
|
||||
"uuid": "9.0.0",
|
||||
"wagmi": "0.12.10"
|
||||
"wagmi": "0.12.10",
|
||||
"zustand": "4.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "13.3.0",
|
||||
|
|
|
|||
923
pnpm-lock.yaml
923
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -25,13 +25,13 @@ ${normalCSS}
|
|||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html:not(.dark):not(.light) {
|
||||
html:not(.light) {
|
||||
${darkCSS}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html:not(.dark):not(.light) {
|
||||
html:not(.dark) {
|
||||
${normalCSS}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,10 +74,10 @@ const transformColorObjectOfDarkmode = () => {
|
|||
black: "var(--tw-colors-i-black)",
|
||||
white: "var(--tw-colors-i-white)",
|
||||
})
|
||||
cssVar["--tw-colors-i-black"] = "0, 0, 0"
|
||||
cssVar["--tw-colors-i-white"] = "255, 255, 255"
|
||||
cssVarDark["--tw-colors-i-black"] = "255, 255, 255"
|
||||
cssVarDark["--tw-colors-i-white"] = "0, 0, 0"
|
||||
cssVar["--tw-colors-i-black"] = "#000"
|
||||
cssVar["--tw-colors-i-white"] = "#fff"
|
||||
cssVarDark["--tw-colors-i-black"] = "#fff"
|
||||
cssVarDark["--tw-colors-i-white"] = "#000"
|
||||
|
||||
return [nextColorObject, cssVar, cssVarDark]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
import { useAccountState } from "@crossbell/connect-kit"
|
||||
import { useRouter } from "next/router"
|
||||
import React, { useEffect } from "react"
|
||||
import { BlockchainInfo } from "~/components/common/BlockchainInfo"
|
||||
import { useUserRole } from "~/hooks/useUserRole"
|
||||
import { IS_PROD } from "~/lib/constants"
|
||||
import { OUR_DOMAIN, SITE_URL } from "~/lib/env"
|
||||
import { toGateway } from "~/lib/ipfs-parser"
|
||||
import { getUserContentsUrl } from "~/lib/user-contents"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { useCheckLike, useCheckMint, useGetPage } from "~/queries/page"
|
||||
import { useGetSite, useGetSubscription } from "~/queries/site"
|
||||
import { SEOHead } from "../common/SEOHead"
|
||||
import { SiteFooter } from "./SiteFooter"
|
||||
import { SiteHeader } from "./SiteHeader"
|
||||
import { useRouter } from "next/router"
|
||||
import { BlockchainInfo } from "~/components/common/BlockchainInfo"
|
||||
import { useGetSite } from "~/queries/site"
|
||||
import { useGetPage } from "~/queries/page"
|
||||
import { OUR_DOMAIN, SITE_URL } from "~/lib/env"
|
||||
import { IS_PROD } from "~/lib/constants"
|
||||
import { toGateway } from "~/lib/ipfs-parser"
|
||||
import { useUserRole } from "~/hooks/useUserRole"
|
||||
import { useGetSubscription } from "~/queries/site"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { useCheckLike, useCheckMint } from "~/queries/page"
|
||||
import { useAccountState } from "@crossbell/connect-kit"
|
||||
|
||||
export type SiteLayoutProps = {
|
||||
children: React.ReactNode
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ 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 { useMediaStore } from "~/hooks/useDarkMode"
|
||||
|
||||
export const Editor: React.FC<{
|
||||
value: string
|
||||
|
|
@ -27,6 +32,9 @@ export const Editor: React.FC<{
|
|||
const { t } = useTranslation("dashboard")
|
||||
const [extensions, setExtensions] = useState<any>([])
|
||||
const isMobileLayout = useMobileLayout()
|
||||
const [editor, setCmEditor] = useState<EditorView | null>(null)
|
||||
const isDark = useMediaStore((state) => state.isDark)
|
||||
useCodeMirrorAutoToggleTheme(editor, isDark)
|
||||
useEffect(() => {
|
||||
setExtensions([
|
||||
markdown(),
|
||||
|
|
@ -46,6 +54,7 @@ export const Editor: React.FC<{
|
|||
},
|
||||
"&.cm-editor": {
|
||||
height: "100%",
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
}),
|
||||
EditorView.domEventHandlers({
|
||||
|
|
@ -82,6 +91,7 @@ export const Editor: React.FC<{
|
|||
},
|
||||
}),
|
||||
EditorView.lineWrapping,
|
||||
...codemirrorReconfigureExtension,
|
||||
])
|
||||
}, [onScroll, handleDropFile])
|
||||
|
||||
|
|
@ -93,7 +103,10 @@ export const Editor: React.FC<{
|
|||
}`}
|
||||
value={value}
|
||||
extensions={extensions}
|
||||
onCreateEditor={onCreateEditor}
|
||||
onCreateEditor={(view, state) => {
|
||||
setCmEditor(view)
|
||||
onCreateEditor?.(view, state)
|
||||
}}
|
||||
basicSetup={{
|
||||
lineNumbers: false,
|
||||
foldGutter: false,
|
||||
|
|
|
|||
|
|
@ -241,6 +241,8 @@
|
|||
--tw-colors-i-rose-800: 159, 18, 57;
|
||||
--tw-colors-i-rose-900: 136, 19, 55;
|
||||
--tw-colors-i-rose-950: 76, 5, 25;
|
||||
--tw-colors-i-black: #000;
|
||||
--tw-colors-i-white: #fff;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
|
|
@ -486,6 +488,8 @@ html.dark {
|
|||
--tw-colors-i-rose-800: 254, 205, 211;
|
||||
--tw-colors-i-rose-900: 255, 228, 230;
|
||||
--tw-colors-i-rose-950: 255, 241, 242;
|
||||
--tw-colors-i-black: #fff;
|
||||
--tw-colors-i-white: #000;
|
||||
}
|
||||
|
||||
html.light {
|
||||
|
|
@ -731,10 +735,12 @@ html.light {
|
|||
--tw-colors-i-rose-800: 159, 18, 57;
|
||||
--tw-colors-i-rose-900: 136, 19, 55;
|
||||
--tw-colors-i-rose-950: 76, 5, 25;
|
||||
--tw-colors-i-black: #000;
|
||||
--tw-colors-i-white: #fff;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html:not(.dark):not(.light) {
|
||||
html:not(.light) {
|
||||
--tw-colors-i-slate-50: 2, 6, 23;
|
||||
--tw-colors-i-slate-100: 15, 23, 42;
|
||||
--tw-colors-i-slate-200: 30, 41, 59;
|
||||
|
|
@ -977,11 +983,13 @@ html.light {
|
|||
--tw-colors-i-rose-800: 254, 205, 211;
|
||||
--tw-colors-i-rose-900: 255, 228, 230;
|
||||
--tw-colors-i-rose-950: 255, 241, 242;
|
||||
--tw-colors-i-black: #fff;
|
||||
--tw-colors-i-white: #000;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html:not(.dark):not(.light) {
|
||||
html:not(.dark) {
|
||||
--tw-colors-i-slate-50: 248, 250, 252;
|
||||
--tw-colors-i-slate-100: 241, 245, 249;
|
||||
--tw-colors-i-slate-200: 226, 232, 240;
|
||||
|
|
@ -1224,5 +1232,7 @@ html.light {
|
|||
--tw-colors-i-rose-800: 159, 18, 57;
|
||||
--tw-colors-i-rose-900: 136, 19, 55;
|
||||
--tw-colors-i-rose-950: 76, 5, 25;
|
||||
--tw-colors-i-black: #000;
|
||||
--tw-colors-i-white: #fff;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
}
|
||||
|
||||
body {
|
||||
@apply break-words;
|
||||
@apply break-words bg-white;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import type { Extension } from "@codemirror/state"
|
||||
import { Compartment } from "@codemirror/state"
|
||||
import { EditorView } from "@codemirror/view"
|
||||
import { useEffect } from "react"
|
||||
|
||||
import { oneDark } from "@codemirror/theme-one-dark"
|
||||
import { githubLight } from "@ddietr/codemirror-themes/theme/github-light"
|
||||
|
||||
const extensionMap = {
|
||||
theme: new Compartment(),
|
||||
}
|
||||
|
||||
export const codemirrorReconfigureExtension: Extension[] = [
|
||||
extensionMap.theme.of([]),
|
||||
]
|
||||
|
||||
export const useCodeMirrorAutoToggleTheme = (
|
||||
view: EditorView | null,
|
||||
isDark: boolean,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!view) return
|
||||
if (isDark) {
|
||||
view.dispatch({
|
||||
effects: [extensionMap.theme.reconfigure(oneDark)],
|
||||
})
|
||||
} else {
|
||||
view.dispatch({
|
||||
effects: [extensionMap.theme.reconfigure(githubLight)],
|
||||
})
|
||||
}
|
||||
}, [view, isDark])
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
import { useEffect, useState } from "react"
|
||||
|
||||
import { create } from "zustand"
|
||||
|
||||
export const useMediaStore = create<{
|
||||
isDark: boolean
|
||||
setDark: (isDark: boolean) => void
|
||||
}>((set) => {
|
||||
return {
|
||||
isDark: false,
|
||||
setDark: (isDark: boolean) => set({ isDark }),
|
||||
}
|
||||
})
|
||||
|
||||
const isServerSide = () => typeof window === "undefined"
|
||||
|
||||
interface DarkModeConfig {
|
||||
classNameDark?: string // A className to set "dark mode". Default = "dark-mode".
|
||||
classNameLight?: string // A className to set "light mode". Default = "light-mode".
|
||||
element?: HTMLElement | undefined | null // The element to apply the className. Default = `document.body`
|
||||
storageKey?: string // Specify the `localStorage` key. Default = "darkMode". Sewt to `null` to disable persistent storage.
|
||||
}
|
||||
|
||||
const useDarkMode = (
|
||||
initialState: boolean | undefined,
|
||||
options: DarkModeConfig,
|
||||
) => {
|
||||
const {
|
||||
classNameDark = "dark",
|
||||
classNameLight = "light",
|
||||
storageKey,
|
||||
element,
|
||||
} = options
|
||||
|
||||
const [darkMode, setDarkMode] = useState(initialState)
|
||||
|
||||
useEffect(() => {
|
||||
const presentedDarkMode = storageKey
|
||||
? isServerSide()
|
||||
? null
|
||||
: localStorage.getItem(storageKey)
|
||||
: null
|
||||
|
||||
if (presentedDarkMode !== null) {
|
||||
if (presentedDarkMode === "true") {
|
||||
setDarkMode(true)
|
||||
} else if (presentedDarkMode === "false") {
|
||||
setDarkMode(false)
|
||||
}
|
||||
} else if (typeof initialState === "undefined") {
|
||||
setDarkMode(window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
}
|
||||
}, [storageKey])
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (e: MediaQueryListEvent) => {
|
||||
const storageValue = localStorage.getItem(storageKey || "darkMode")
|
||||
if (storageValue === null) {
|
||||
setDarkMode(e.matches)
|
||||
}
|
||||
}
|
||||
|
||||
const focusHandler = () => {
|
||||
const storageValue = localStorage.getItem(storageKey || "darkMode")
|
||||
if (storageValue === null) {
|
||||
setDarkMode(window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("focus", focusHandler)
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", handler)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("focus", focusHandler)
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.removeEventListener("change", handler)
|
||||
}
|
||||
}, [storageKey])
|
||||
|
||||
useEffect(() => {
|
||||
if (isServerSide()) {
|
||||
return
|
||||
}
|
||||
|
||||
const $el = element || document.documentElement
|
||||
if (darkMode) {
|
||||
$el.classList.remove(classNameLight)
|
||||
$el.classList.add(classNameDark)
|
||||
} else {
|
||||
$el.classList.remove(classNameDark)
|
||||
$el.classList.add(classNameLight)
|
||||
}
|
||||
}, [classNameDark, classNameLight, darkMode, element])
|
||||
|
||||
if (isServerSide()) {
|
||||
return {
|
||||
toggle: () => {},
|
||||
value: false,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value: darkMode,
|
||||
toggle: () => {
|
||||
setDarkMode((d) => {
|
||||
if (storageKey && !isServerSide()) {
|
||||
localStorage.setItem(storageKey, String(!d))
|
||||
}
|
||||
|
||||
return !d
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
const mockElement = {
|
||||
classList: {
|
||||
add: noop,
|
||||
remove: noop,
|
||||
},
|
||||
}
|
||||
const darkModeKey = "darkMode"
|
||||
export const useMediaToggle = () => {
|
||||
const { toggle, value } = useDarkMode(undefined, {
|
||||
classNameDark: "dark",
|
||||
classNameLight: "light",
|
||||
storageKey: darkModeKey,
|
||||
element: (globalThis.document && document.documentElement) || mockElement,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
useMediaStore.getState().setDark(value ? true : false)
|
||||
}, [value])
|
||||
|
||||
useEffect(() => {
|
||||
const handler = () => {
|
||||
if (window.matchMedia("(prefers-color-scheme: dark)").matches === value) {
|
||||
localStorage.removeItem(darkModeKey)
|
||||
}
|
||||
}
|
||||
window.addEventListener("beforeunload", handler)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("beforeunload", handler)
|
||||
}
|
||||
}, [value])
|
||||
|
||||
return {
|
||||
toggle,
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import { toGateway } from "~/lib/ipfs-parser"
|
|||
import { createIDBPersister } from "~/lib/persister.client"
|
||||
import { urlComposer } from "~/lib/url-composer"
|
||||
import { AppPropsWithLayout } from "types/next"
|
||||
import { useMediaToggle } from "~/hooks/useDarkMode"
|
||||
|
||||
Network.setIpfsGateway(IPFS_GATEWAY)
|
||||
|
||||
|
|
|
|||
|
|
@ -635,7 +635,7 @@ export default function SubdomainEditor() {
|
|||
}
|
||||
}}
|
||||
onChange={(e) => updateValue("title", e.target.value)}
|
||||
className="h-12 ml-1 inline-flex items-center border-none text-3xl font-bold w-full focus:outline-none"
|
||||
className="h-12 ml-1 inline-flex items-center border-none text-3xl font-bold w-full focus:outline-none bg-white"
|
||||
placeholder={t("Title goes here...") || ""}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -285,4 +285,9 @@ export default {
|
|||
900: "rgba(var(--tw-colors-i-rose-900), <alpha-value>)",
|
||||
950: "rgba(var(--tw-colors-i-rose-950), <alpha-value>)",
|
||||
},
|
||||
inherit: "inherit",
|
||||
current: "currentColor",
|
||||
transparent: "transparent",
|
||||
black: "var(--tw-colors-i-black)",
|
||||
white: "var(--tw-colors-i-white)",
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue