mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-05-02 21:50:10 +00:00
minor fixes
This commit is contained in:
parent
e1af1d0b59
commit
a843edde5e
100 changed files with 772 additions and 15434 deletions
|
|
@ -1,32 +0,0 @@
|
|||
"use client"
|
||||
|
||||
import { createContext, type ReactNode, useContext, useState } from "react"
|
||||
|
||||
type ActivePanel = "menu" | "chat" | null
|
||||
|
||||
interface MobilePanelContextType {
|
||||
activePanel: ActivePanel
|
||||
setActivePanel: (panel: ActivePanel) => void
|
||||
}
|
||||
|
||||
const MobilePanelContext = createContext<MobilePanelContextType | undefined>(
|
||||
undefined,
|
||||
)
|
||||
|
||||
export function MobilePanelProvider({ children }: { children: ReactNode }) {
|
||||
const [activePanel, setActivePanel] = useState<ActivePanel>(null)
|
||||
|
||||
return (
|
||||
<MobilePanelContext.Provider value={{ activePanel, setActivePanel }}>
|
||||
{children}
|
||||
</MobilePanelContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useMobilePanel() {
|
||||
const context = useContext(MobilePanelContext)
|
||||
if (!context) {
|
||||
throw new Error("useMobilePanel must be used within a MobilePanelProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
28
apps/web/lib/search-params.ts
Normal file
28
apps/web/lib/search-params.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import {
|
||||
parseAsString,
|
||||
parseAsBoolean,
|
||||
parseAsStringLiteral,
|
||||
parseAsArrayOf,
|
||||
} from "nuqs"
|
||||
|
||||
// Modal states
|
||||
export const addDocumentParam = parseAsStringLiteral([
|
||||
"note",
|
||||
"link",
|
||||
"file",
|
||||
"connect",
|
||||
] as const)
|
||||
export const mcpParam = parseAsBoolean.withDefault(false)
|
||||
export const searchParam = parseAsBoolean.withDefault(false)
|
||||
export const qParam = parseAsString.withDefault("")
|
||||
export const docParam = parseAsString
|
||||
export const fullscreenParam = parseAsBoolean.withDefault(false)
|
||||
export const chatParam = parseAsBoolean
|
||||
export const threadParam = parseAsString
|
||||
export const shareParam = parseAsBoolean.withDefault(false)
|
||||
export const feedbackParam = parseAsBoolean.withDefault(false)
|
||||
|
||||
// View & filter states
|
||||
export const viewParam = parseAsStringLiteral(["graph", "list"] as const).withDefault("graph")
|
||||
export const categoriesParam = parseAsArrayOf(parseAsString, ",").withDefault([])
|
||||
export const projectParam = parseAsString.withDefault("sm_project_default")
|
||||
|
|
@ -1,96 +1,22 @@
|
|||
"use client"
|
||||
|
||||
import {
|
||||
createContext,
|
||||
type ReactNode,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react"
|
||||
import { useQueryState } from "nuqs"
|
||||
import { viewParam } from "@/lib/search-params"
|
||||
import { analytics } from "@/lib/analytics"
|
||||
import { useCallback } from "react"
|
||||
|
||||
type ViewMode = "graph" | "list"
|
||||
|
||||
interface ViewModeContextType {
|
||||
viewMode: ViewMode
|
||||
setViewMode: (mode: ViewMode) => void
|
||||
isInitialized: boolean
|
||||
}
|
||||
|
||||
const ViewModeContext = createContext<ViewModeContextType | undefined>(
|
||||
undefined,
|
||||
)
|
||||
|
||||
// Cookie utility functions
|
||||
const setCookie = (name: string, value: string, days = 365) => {
|
||||
if (typeof document === "undefined") return
|
||||
const expires = new Date()
|
||||
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000)
|
||||
document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/`
|
||||
}
|
||||
|
||||
const getCookie = (name: string): string | null => {
|
||||
if (typeof document === "undefined") return null
|
||||
const nameEQ = `${name}=`
|
||||
const ca = document.cookie.split(";")
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i]
|
||||
if (!c) continue
|
||||
while (c.charAt(0) === " ") c = c.substring(1, c.length)
|
||||
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const isMobileDevice = () => {
|
||||
if (typeof window === "undefined") return false
|
||||
return window.innerWidth < 768
|
||||
}
|
||||
|
||||
export function ViewModeProvider({ children }: { children: ReactNode }) {
|
||||
// Start with a default that works for SSR
|
||||
const [viewMode, setViewModeState] = useState<ViewMode>("graph")
|
||||
const [isInitialized, setIsInitialized] = useState(false)
|
||||
|
||||
// Load preferences on the client side
|
||||
useEffect(() => {
|
||||
if (!isInitialized) {
|
||||
// Check for saved preference first
|
||||
const savedMode = getCookie("memoryViewMode")
|
||||
if (savedMode === "list" || savedMode === "graph") {
|
||||
setViewModeState(savedMode)
|
||||
} else {
|
||||
// If no saved preference, default to list on mobile, graph on desktop
|
||||
setViewModeState(isMobileDevice() ? "list" : "graph")
|
||||
}
|
||||
setIsInitialized(true)
|
||||
}
|
||||
}, [isInitialized])
|
||||
|
||||
// Save to cookie whenever view mode changes
|
||||
const handleSetViewMode = (mode: ViewMode) => {
|
||||
analytics.viewModeChanged(mode)
|
||||
setViewModeState(mode)
|
||||
setCookie("memoryViewMode", mode)
|
||||
}
|
||||
|
||||
return (
|
||||
<ViewModeContext.Provider
|
||||
value={{
|
||||
viewMode,
|
||||
setViewMode: handleSetViewMode,
|
||||
isInitialized,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ViewModeContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useViewMode() {
|
||||
const context = useContext(ViewModeContext)
|
||||
if (!context) {
|
||||
throw new Error("useViewMode must be used within a ViewModeProvider")
|
||||
}
|
||||
return context
|
||||
const [viewMode, _setViewMode] = useQueryState("view", viewParam)
|
||||
|
||||
const setViewMode = useCallback(
|
||||
(mode: ViewMode) => {
|
||||
analytics.viewModeChanged(mode)
|
||||
_setViewMode(mode)
|
||||
},
|
||||
[_setViewMode],
|
||||
)
|
||||
|
||||
return { viewMode, setViewMode, isInitialized: true }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue