layout-context.tsx 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { createContext, useContext, useEffect, useState } from 'react'
  2. import { getCookie, setCookie } from '@/lib/cookies'
  3. export type Collapsible = 'offcanvas' | 'icon' | 'none'
  4. export type Variant = 'inset' | 'sidebar' | 'floating'
  5. // Cookie constants following the pattern from sidebar.tsx
  6. const LAYOUT_COLLAPSIBLE_COOKIE_NAME = 'layout_collapsible'
  7. const LAYOUT_VARIANT_COOKIE_NAME = 'layout_variant'
  8. const LAYOUT_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 // 7 days
  9. // Default values
  10. const DEFAULT_VARIANT = 'inset'
  11. const DEFAULT_COLLAPSIBLE = 'icon'
  12. interface LayoutContextType {
  13. resetLayout: () => void
  14. defaultCollapsible: Collapsible
  15. collapsible: Collapsible
  16. setCollapsible: (collapsible: Collapsible) => void
  17. defaultVariant: Variant
  18. variant: Variant
  19. setVariant: (variant: Variant) => void
  20. }
  21. const LayoutContext = createContext<LayoutContextType>({
  22. resetLayout: () => {},
  23. defaultCollapsible: DEFAULT_COLLAPSIBLE,
  24. collapsible: DEFAULT_COLLAPSIBLE,
  25. setCollapsible: () => {},
  26. defaultVariant: DEFAULT_VARIANT,
  27. variant: DEFAULT_VARIANT,
  28. setVariant: () => {},
  29. })
  30. interface LayoutProviderProps {
  31. children: React.ReactNode
  32. }
  33. export function LayoutProvider({ children }: LayoutProviderProps) {
  34. const [collapsible, setCollapsible] = useState<Collapsible>(
  35. () =>
  36. (getCookie(LAYOUT_COLLAPSIBLE_COOKIE_NAME) as Collapsible) ||
  37. DEFAULT_COLLAPSIBLE
  38. )
  39. const [variant, setVariant] = useState<Variant>(
  40. () => (getCookie(LAYOUT_VARIANT_COOKIE_NAME) as Variant) || DEFAULT_VARIANT
  41. )
  42. useEffect(() => {
  43. setCookie(
  44. LAYOUT_COLLAPSIBLE_COOKIE_NAME,
  45. collapsible,
  46. LAYOUT_COOKIE_MAX_AGE
  47. )
  48. }, [collapsible])
  49. useEffect(() => {
  50. setCookie(LAYOUT_VARIANT_COOKIE_NAME, variant, LAYOUT_COOKIE_MAX_AGE)
  51. }, [variant])
  52. const resetLayout = () => {
  53. setCollapsible(DEFAULT_COLLAPSIBLE)
  54. setVariant(DEFAULT_VARIANT)
  55. }
  56. return (
  57. <LayoutContext
  58. value={{
  59. defaultCollapsible: DEFAULT_COLLAPSIBLE,
  60. defaultVariant: DEFAULT_VARIANT,
  61. resetLayout,
  62. collapsible,
  63. setCollapsible,
  64. variant,
  65. setVariant,
  66. }}
  67. >
  68. {children}
  69. </LayoutContext>
  70. )
  71. }
  72. // Define the hook for the provider
  73. // eslint-disable-next-line react-refresh/only-export-components
  74. export function useLayout() {
  75. const context = useContext(LayoutContext)
  76. if (!context) {
  77. throw new Error('useLayout must be used within a LayoutProvider')
  78. }
  79. return context
  80. }