mirror of
https://github.com/acid-info/logos-ordinals-dashboard.git
synced 2025-02-05 01:53:49 +00:00
feat: replace hookstate with jotai
This commit is contained in:
parent
2dc90344d9
commit
9d0a517fa6
@ -25,16 +25,14 @@
|
||||
"@acid-info/lsd-react": "^0.1.0-beta.3",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@hookstate/core": "^4.0.1",
|
||||
"@hookstate/localstored": "^4.0.2",
|
||||
"@mdx-js/loader": "^2.3.0",
|
||||
"@mdx-js/react": "^2.3.0",
|
||||
"@next/font": "^14.2.13",
|
||||
"@next/mdx": "^13.5.5",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@types/mdx": "^2.0.8",
|
||||
"@vercel/og": "^0.5.4",
|
||||
"axios": "^1.4.0",
|
||||
"jotai": "^2.10.1",
|
||||
"lazysizes": "^5.3.2",
|
||||
"next": "^14.2.3",
|
||||
"next-mdx-remote": "^4.4.1",
|
||||
|
@ -1,20 +1,21 @@
|
||||
import { defaultFilterState } from '@/states/filterState'
|
||||
import styled from '@emotion/styled'
|
||||
import { hookstate, useHookstate } from '@hookstate/core'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import Checkbox from './Checkbox' // Import the CustomCheckbox
|
||||
import Checkbox from './Checkbox'
|
||||
|
||||
interface DropdownProps {
|
||||
title: string
|
||||
options: string[]
|
||||
filterType: string
|
||||
onSelectionChange: (selectedOptions: string[], filterType: string) => void
|
||||
filterType: keyof typeof defaultFilterState
|
||||
onSelectionChange: (
|
||||
selectedOptions: string[],
|
||||
filterType: keyof typeof defaultFilterState,
|
||||
) => void
|
||||
prefill?: string[]
|
||||
}
|
||||
|
||||
const globalState = hookstate(() =>
|
||||
JSON.parse(JSON.stringify(defaultFilterState)),
|
||||
)
|
||||
const filterAtom = atom(defaultFilterState)
|
||||
|
||||
const Dropdown: React.FC<DropdownProps> = ({
|
||||
title,
|
||||
@ -29,17 +30,17 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const state = useHookstate(globalState)
|
||||
const [filter, setFilter] = useAtom(filterAtom)
|
||||
|
||||
const defualtState = state.get()
|
||||
const defaultState = defaultFilterState
|
||||
|
||||
useEffect(() => {
|
||||
if (defualtState[filterType]?.length === selectedOptions?.length) {
|
||||
if (defaultState[filterType]?.length === selectedOptions?.length) {
|
||||
setUpdated(false)
|
||||
} else {
|
||||
setUpdated(true)
|
||||
}
|
||||
}, [defualtState, selectedOptions])
|
||||
}, [defaultState, selectedOptions, filterType])
|
||||
|
||||
useEffect(() => {
|
||||
if (prefill?.length) {
|
||||
@ -56,16 +57,23 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
}
|
||||
|
||||
const handleSelect = (option: string) => {
|
||||
let newSelectedOptions = []
|
||||
let newSelectedOptions: any = []
|
||||
|
||||
if (selectedOptions.includes(option)) {
|
||||
newSelectedOptions = selectedOptions.filter((o) => o !== option)
|
||||
} else {
|
||||
newSelectedOptions = [...selectedOptions, option]
|
||||
}
|
||||
|
||||
setSelectedOptions(newSelectedOptions)
|
||||
onSelectionChange(newSelectedOptions, filterType)
|
||||
|
||||
handleUpdate(newSelectedOptions)
|
||||
|
||||
setFilter((prev) => ({
|
||||
...prev,
|
||||
[filterType]: newSelectedOptions,
|
||||
}))
|
||||
}
|
||||
|
||||
const selectAll = () => {
|
||||
@ -73,6 +81,11 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
onSelectionChange(options, filterType)
|
||||
|
||||
setUpdated(false)
|
||||
|
||||
setFilter((prev) => ({
|
||||
...prev,
|
||||
[filterType]: options,
|
||||
}))
|
||||
}
|
||||
|
||||
const clearAll = () => {
|
||||
@ -80,6 +93,11 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
onSelectionChange([], filterType)
|
||||
|
||||
setUpdated(true)
|
||||
|
||||
setFilter((prev) => ({
|
||||
...prev,
|
||||
[filterType]: [],
|
||||
}))
|
||||
}
|
||||
|
||||
const toggleDropdown = () => {
|
||||
@ -139,8 +157,6 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
)
|
||||
}
|
||||
|
||||
// Additional styled components for Dropdown
|
||||
|
||||
const DropdownContainer = styled.div`
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
@ -219,7 +235,6 @@ const ScrollDiv = styled.div`
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
// white scrollbar
|
||||
&::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Dropdown } from '@/components/Dropdown'
|
||||
import { OperatorGrid } from '@/components/Explore/OperatorGrid'
|
||||
import { defaultFilterState } from '@/states/filterState'
|
||||
import { defaultFilterState, FilterState } from '@/states/filterState'
|
||||
import styled from '@emotion/styled'
|
||||
import { hookstate, useHookstate } from '@hookstate/core'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import useGetOperators from '../../../apis/operators/useGetOperators'
|
||||
import {
|
||||
@ -17,15 +17,12 @@ import { processOperators, shuffleOperators } from '../../../utils/operators'
|
||||
|
||||
interface ExploreSectionProps {}
|
||||
|
||||
const globalState = hookstate(() =>
|
||||
JSON.parse(JSON.stringify(defaultFilterState)),
|
||||
)
|
||||
const filterAtom = atom<FilterState>(defaultFilterState)
|
||||
|
||||
const ExploreSection: React.FC<ExploreSectionProps> = () => {
|
||||
const { data, isLoading } = useGetOperators()
|
||||
|
||||
const state = useHookstate(globalState)
|
||||
const filter = state.get()
|
||||
const [filter, setFilter] = useAtom(filterAtom)
|
||||
|
||||
const processedOperators = processOperators(
|
||||
data as any,
|
||||
@ -47,15 +44,17 @@ const ExploreSection: React.FC<ExploreSectionProps> = () => {
|
||||
|
||||
const handleFilterChange = (
|
||||
selectedOptions: string[],
|
||||
filterType: string,
|
||||
filterType: keyof typeof filter,
|
||||
) => {
|
||||
// @ts-ignore
|
||||
state[filterType].set(selectedOptions)
|
||||
setFilter((prev) => ({
|
||||
...prev,
|
||||
[filterType]: selectedOptions,
|
||||
}))
|
||||
}
|
||||
|
||||
const handleResetAll = useCallback(() => {
|
||||
state.set(JSON.parse(JSON.stringify(defaultFilterState)))
|
||||
}, [filter])
|
||||
setFilter(JSON.parse(JSON.stringify(defaultFilterState)))
|
||||
}, [setFilter])
|
||||
|
||||
return (
|
||||
<Container>
|
||||
@ -104,7 +103,7 @@ const ExploreSection: React.FC<ExploreSectionProps> = () => {
|
||||
prefill={filter.background.slice()}
|
||||
/>
|
||||
<ResetAll onClick={handleResetAll}>
|
||||
Reset All <img src="/assets/close-black.svg" />
|
||||
Reset All <img src="/assets/close-black.svg" alt="close-black" />
|
||||
</ResetAll>
|
||||
</DropdownContainer>
|
||||
<OperatorGrid
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ThemeProvider, ThemeProviderProps } from '@acid-info/lsd-react'
|
||||
import { Global } from '@emotion/react'
|
||||
import React, { useEffect } from 'react'
|
||||
import useThemeState from '../../states/themeState/theme.state'
|
||||
import { useThemeState } from '../../states/themeState/theme.state' // Using Jotai's useThemeState hook
|
||||
import { useLSDTheme } from './themes'
|
||||
|
||||
export type LSDThemeProviderProps = Partial<ThemeProviderProps>
|
||||
@ -15,9 +15,9 @@ export const LSDThemeProvider: React.FC<LSDThemeProviderProps> = ({
|
||||
|
||||
useEffect(() => {
|
||||
const html = document.querySelector('html') as HTMLElement
|
||||
html.setAttribute('data-theme', mode.value)
|
||||
html.setAttribute('data-font-family', genericFontFamily.value)
|
||||
}, [mode.value, genericFontFamily.value])
|
||||
html.setAttribute('data-theme', mode) // Removed `.value` since Jotai provides direct values
|
||||
html.setAttribute('data-font-family', genericFontFamily) // Removed `.value`
|
||||
}, [mode, genericFontFamily]) // Removed `.value` in dependencies
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme.current} injectCssVars={false}>
|
||||
|
@ -33,7 +33,7 @@ const useThemeCssVars = (theme: Theme, colorMode: string) =>
|
||||
)
|
||||
|
||||
export const useLSDTheme = () => {
|
||||
const { genericFontFamily, mode } = useThemeState().get()
|
||||
const { genericFontFamily, mode } = useThemeState()
|
||||
|
||||
const themes = useMemo(() => {
|
||||
const options: CreateThemeProps = {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { hookstate, State, useHookstate } from '@hookstate/core'
|
||||
import { localstored } from '@hookstate/localstored'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
import {
|
||||
ARCHETYPE,
|
||||
BACKGROUND,
|
||||
@ -28,17 +27,20 @@ export const defaultFilterState: FilterState = {
|
||||
background: BACKGROUND,
|
||||
}
|
||||
|
||||
const filterState =
|
||||
typeof window === 'undefined'
|
||||
? hookstate(defaultFilterState)
|
||||
: hookstate<FilterState>(defaultFilterState, localstored({ key: 'filter' }))
|
||||
const filterAtom = atom<FilterState>(defaultFilterState)
|
||||
|
||||
const wrapFilterState = (state: State<FilterState>) => ({
|
||||
filter: { ...state.value },
|
||||
get: () => state.value,
|
||||
setFilter: (value: FilterState) => state.set(value),
|
||||
const wrapFilterState = (
|
||||
filter: FilterState,
|
||||
setFilter: (value: FilterState) => void,
|
||||
) => ({
|
||||
filter,
|
||||
get: () => filter,
|
||||
setFilter: (value: FilterState) => setFilter(value),
|
||||
})
|
||||
|
||||
export const useFilterState = () => wrapFilterState(useHookstate(filterState))
|
||||
export const useFilterState = () => {
|
||||
const [filter, setFilter] = useAtom(filterAtom)
|
||||
return wrapFilterState(filter, setFilter)
|
||||
}
|
||||
|
||||
export default useFilterState
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { TypographyGenericFontFamily } from '@acid-info/lsd-react'
|
||||
import { hookstate, State, useHookstate } from '@hookstate/core'
|
||||
import { localstored } from '@hookstate/localstored'
|
||||
import { atom, useAtom } from 'jotai'
|
||||
|
||||
export type ThemeState = {
|
||||
mode: 'light' | 'dark'
|
||||
@ -12,24 +11,61 @@ export const defaultThemeState: ThemeState = {
|
||||
genericFontFamily: 'Inter',
|
||||
}
|
||||
|
||||
const themeState =
|
||||
typeof window === 'undefined'
|
||||
? hookstate(defaultThemeState)
|
||||
: hookstate<ThemeState>(defaultThemeState, localstored({ key: 'theme' }))
|
||||
|
||||
const wrapThemeState = (state: State<ThemeState>) => ({
|
||||
mode: state.mode,
|
||||
genericFontFamily: state.genericFontFamily,
|
||||
get: () => state.value,
|
||||
setMode: (value: ThemeState['mode']) => state.mode.set(value),
|
||||
setGenericFontFamily: (value: ThemeState['genericFontFamily']) =>
|
||||
state.genericFontFamily.set('Inter'),
|
||||
toggleMode: () =>
|
||||
state.mode.set(state.mode.get() === 'dark' ? 'light' : 'dark'),
|
||||
const themeAtom = atom<ThemeState>(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const storedTheme = localStorage.getItem('theme')
|
||||
return storedTheme ? JSON.parse(storedTheme) : defaultThemeState
|
||||
}
|
||||
return defaultThemeState
|
||||
})
|
||||
|
||||
export const useThemeState = () => wrapThemeState(useHookstate(themeState))
|
||||
const persistentThemeAtom = atom(
|
||||
(get) => get(themeAtom),
|
||||
(get, set, newTheme: ThemeState) => {
|
||||
set(JSON.parse(JSON.stringify(newTheme)))
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('theme', JSON.stringify(newTheme))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
export const useIsDarkTheme = () => useThemeState().mode.get() === 'dark'
|
||||
export const useThemeState = () => {
|
||||
const [theme, setTheme] = useAtom(persistentThemeAtom)
|
||||
|
||||
const setMode = (mode: ThemeState['mode']) => {
|
||||
setTheme({
|
||||
...theme,
|
||||
mode,
|
||||
})
|
||||
}
|
||||
|
||||
const setGenericFontFamily = (
|
||||
fontFamily: ThemeState['genericFontFamily'],
|
||||
) => {
|
||||
setTheme({
|
||||
...theme,
|
||||
genericFontFamily: fontFamily,
|
||||
})
|
||||
}
|
||||
|
||||
const toggleMode = () => {
|
||||
setTheme({
|
||||
...theme,
|
||||
mode: theme.mode === 'dark' ? 'light' : 'dark',
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...theme,
|
||||
setMode,
|
||||
setGenericFontFamily,
|
||||
toggleMode,
|
||||
}
|
||||
}
|
||||
|
||||
export const useIsDarkTheme = () => {
|
||||
const theme = useThemeState()
|
||||
return theme.mode === 'dark'
|
||||
}
|
||||
|
||||
export default useThemeState
|
||||
|
20
yarn.lock
20
yarn.lock
@ -267,16 +267,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa"
|
||||
integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==
|
||||
|
||||
"@hookstate/core@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@hookstate/core/-/core-4.0.1.tgz#6744380e96ce13fe3488c926c1cbae93bbea0ff6"
|
||||
integrity sha512-Uh2D8Z0z/pqOJ7t+SfC+2sj13JQcB4yFhtL+T1choCaBxTSlgOS/CKRBohgJ4cjTKoxOmTT8uSQysu3gUjX+Gw==
|
||||
|
||||
"@hookstate/localstored@^4.0.2":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@hookstate/localstored/-/localstored-4.0.2.tgz#6f0ef6b71baa4c28e5e8835431585500eb6a9532"
|
||||
integrity sha512-81dbUH6xnwbePby21NQN8zrmjvMA8tOYeOOLZXqRmRGKnhtcokjTJoRNMZugpC9P3/NnacllBZ5ZUt43nmrKkA==
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.11":
|
||||
version "0.11.11"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
|
||||
@ -364,11 +354,6 @@
|
||||
dependencies:
|
||||
glob "10.3.10"
|
||||
|
||||
"@next/font@^14.2.13":
|
||||
version "14.2.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/font/-/font-14.2.13.tgz#cfe0903654e65b58e7b5cdc600399a45e028bbdb"
|
||||
integrity sha512-xtleJ172yNVSVoQoMIwPHnM9zSPOzNB964mZMOFmRaLWgWMgmlhCVI42dlDSGc6d9nQ/WHCmCZaJMloS1HHGXg==
|
||||
|
||||
"@next/mdx@^13.5.5":
|
||||
version "13.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-13.5.5.tgz#ce1ff29ab424f2335a02ac6a662f56938c275b5d"
|
||||
@ -2562,6 +2547,11 @@ jackspeak@^2.3.5:
|
||||
optionalDependencies:
|
||||
"@pkgjs/parseargs" "^0.11.0"
|
||||
|
||||
jotai@^2.10.1:
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.10.1.tgz#8d5598d06fa295110de0914f10bd1d10ea229723"
|
||||
integrity sha512-4FycO+BOTl2auLyF2Chvi6KTDqdsdDDtpaL/WHQMs8f3KS1E3loiUShQzAzFA/sMU5cJ0hz/RT1xum9YbG/zaA==
|
||||
|
||||
js-cookie@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||
|
Loading…
x
Reference in New Issue
Block a user