Compare commits
1 Commits
persist-pr
...
proj-styli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9051d80775 |
@@ -1,11 +1,10 @@
|
|||||||
import { Box, type BoxProps } from "@chakra-ui/react";
|
import { Box, type BoxProps, forwardRef } from "@chakra-ui/react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
const NavSidebarOption = ({
|
const NavSidebarOption = forwardRef<
|
||||||
activeHrefPattern,
|
{ activeHrefPattern?: string; disableHoverEffect?: boolean } & BoxProps,
|
||||||
disableHoverEffect,
|
"div"
|
||||||
...props
|
>(({ activeHrefPattern, disableHoverEffect, ...props }, ref) => {
|
||||||
}: { activeHrefPattern?: string; disableHoverEffect?: boolean } & BoxProps) => {
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const isActive = activeHrefPattern && router.pathname.startsWith(activeHrefPattern);
|
const isActive = activeHrefPattern && router.pathname.startsWith(activeHrefPattern);
|
||||||
return (
|
return (
|
||||||
@@ -18,10 +17,13 @@ const NavSidebarOption = ({
|
|||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
borderRadius={4}
|
borderRadius={4}
|
||||||
{...props}
|
{...props}
|
||||||
|
ref={ref}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
|
NavSidebarOption.displayName = "NavSidebarOption";
|
||||||
|
|
||||||
export default NavSidebarOption;
|
export default NavSidebarOption;
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ import {
|
|||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { AiFillCaretDown } from "react-icons/ai";
|
import { BsChevronRight, BsGear, BsPlus } from "react-icons/bs";
|
||||||
import { BsGear, BsPlus } from "react-icons/bs";
|
|
||||||
import { type Project } from "@prisma/client";
|
import { type Project } from "@prisma/client";
|
||||||
|
|
||||||
import { useAppStore } from "~/state/store";
|
import { useAppStore } from "~/state/store";
|
||||||
@@ -68,14 +67,9 @@ export default function ProjectMenu() {
|
|||||||
>
|
>
|
||||||
PROJECT
|
PROJECT
|
||||||
</Text>
|
</Text>
|
||||||
<NavSidebarOption>
|
<Popover placement="right" isOpen={popover.isOpen} onClose={popover.onClose} closeOnBlur>
|
||||||
<Popover
|
<PopoverTrigger>
|
||||||
placement="bottom-start"
|
<NavSidebarOption>
|
||||||
isOpen={popover.isOpen}
|
|
||||||
onClose={popover.onClose}
|
|
||||||
closeOnBlur
|
|
||||||
>
|
|
||||||
<PopoverTrigger>
|
|
||||||
<HStack w="full" onClick={popover.onToggle}>
|
<HStack w="full" onClick={popover.onToggle}>
|
||||||
<Flex
|
<Flex
|
||||||
p={1}
|
p={1}
|
||||||
@@ -92,46 +86,41 @@ export default function ProjectMenu() {
|
|||||||
<Text fontSize="sm" display={{ base: "none", md: "block" }} py={1} flex={1}>
|
<Text fontSize="sm" display={{ base: "none", md: "block" }} py={1} flex={1}>
|
||||||
{selectedProject?.name}
|
{selectedProject?.name}
|
||||||
</Text>
|
</Text>
|
||||||
<Icon as={AiFillCaretDown} boxSize={3} size="xs" color="gray.500" mr={2} />
|
<Icon as={BsChevronRight} boxSize={4} color="gray.500" />
|
||||||
</HStack>
|
</HStack>
|
||||||
</PopoverTrigger>
|
</NavSidebarOption>
|
||||||
<PopoverContent
|
</PopoverTrigger>
|
||||||
_focusVisible={{ boxShadow: "unset" }}
|
<PopoverContent _focusVisible={{ outline: "unset" }} ml={-1}>
|
||||||
minW={0}
|
<VStack alignItems="flex-start" spacing={2} py={4} px={2}>
|
||||||
borderColor="blue.400"
|
<Text color="gray.500" fontSize="xs" fontWeight="bold" pb={1}>
|
||||||
w="full"
|
PROJECTS
|
||||||
>
|
</Text>
|
||||||
<VStack alignItems="flex-start" spacing={2} py={4} px={2}>
|
<Divider />
|
||||||
<Text color="gray.500" fontSize="xs" fontWeight="bold" pb={1}>
|
<VStack spacing={0} w="full">
|
||||||
PROJECTS
|
{projects?.map((proj) => (
|
||||||
</Text>
|
<ProjectOption
|
||||||
<Divider />
|
key={proj.id}
|
||||||
<VStack spacing={0} w="full">
|
proj={proj}
|
||||||
{projects?.map((proj) => (
|
isActive={proj.id === selectedProjectId}
|
||||||
<ProjectOption
|
onClose={popover.onClose}
|
||||||
key={proj.id}
|
/>
|
||||||
proj={proj}
|
))}
|
||||||
isActive={proj.id === selectedProjectId}
|
|
||||||
onClose={popover.onClose}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</VStack>
|
|
||||||
<HStack
|
|
||||||
as={Button}
|
|
||||||
variant="ghost"
|
|
||||||
colorScheme="blue"
|
|
||||||
color="blue.400"
|
|
||||||
pr={8}
|
|
||||||
w="full"
|
|
||||||
onClick={createProject}
|
|
||||||
>
|
|
||||||
<Icon as={isLoading ? Spinner : BsPlus} boxSize={6} />
|
|
||||||
<Text>New project</Text>
|
|
||||||
</HStack>
|
|
||||||
</VStack>
|
</VStack>
|
||||||
</PopoverContent>
|
<HStack
|
||||||
</Popover>
|
as={Button}
|
||||||
</NavSidebarOption>
|
variant="ghost"
|
||||||
|
colorScheme="blue"
|
||||||
|
color="blue.400"
|
||||||
|
pr={8}
|
||||||
|
w="full"
|
||||||
|
onClick={createProject}
|
||||||
|
>
|
||||||
|
<Icon as={isLoading ? Spinner : BsPlus} boxSize={6} />
|
||||||
|
<Text>New project</Text>
|
||||||
|
</HStack>
|
||||||
|
</VStack>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
Link,
|
Link,
|
||||||
type StackProps,
|
type StackProps,
|
||||||
Box,
|
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { type Session } from "next-auth";
|
import { type Session } from "next-auth";
|
||||||
import { signOut } from "next-auth/react";
|
import { signOut } from "next-auth/react";
|
||||||
@@ -27,30 +26,28 @@ export default function UserMenu({ user, ...rest }: { user: Session } & StackPro
|
|||||||
<>
|
<>
|
||||||
<Popover placement="right">
|
<Popover placement="right">
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<Box>
|
<NavSidebarOption>
|
||||||
<NavSidebarOption>
|
<HStack
|
||||||
<HStack
|
// Weird values to make mobile look right; can clean up when we make the sidebar disappear on mobile
|
||||||
// Weird values to make mobile look right; can clean up when we make the sidebar disappear on mobile
|
py={2}
|
||||||
py={2}
|
px={1}
|
||||||
px={1}
|
spacing={3}
|
||||||
spacing={3}
|
{...rest}
|
||||||
{...rest}
|
>
|
||||||
>
|
{profileImage}
|
||||||
{profileImage}
|
<VStack spacing={0} align="start" flex={1} flexShrink={1}>
|
||||||
<VStack spacing={0} align="start" flex={1} flexShrink={1}>
|
<Text fontWeight="bold" fontSize="sm">
|
||||||
<Text fontWeight="bold" fontSize="sm">
|
{user.user.name}
|
||||||
{user.user.name}
|
</Text>
|
||||||
</Text>
|
<Text color="gray.500" fontSize="xs">
|
||||||
<Text color="gray.500" fontSize="xs">
|
{/* {user.user.email} */}
|
||||||
{/* {user.user.email} */}
|
</Text>
|
||||||
</Text>
|
</VStack>
|
||||||
</VStack>
|
<Icon as={BsChevronRight} boxSize={4} color="gray.500" />
|
||||||
<Icon as={BsChevronRight} boxSize={4} color="gray.500" />
|
</HStack>
|
||||||
</HStack>
|
</NavSidebarOption>
|
||||||
</NavSidebarOption>
|
|
||||||
</Box>
|
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent _focusVisible={{ boxShadow: "unset", outline: "unset" }} maxW="200px">
|
<PopoverContent _focusVisible={{ outline: "unset" }} ml={-1}>
|
||||||
<VStack align="stretch" spacing={0}>
|
<VStack align="stretch" spacing={0}>
|
||||||
{/* sign out */}
|
{/* sign out */}
|
||||||
<HStack
|
<HStack
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { PersistOptions } from "zustand/middleware/persist";
|
|
||||||
import { State } from "./store";
|
|
||||||
|
|
||||||
export const stateToPersist = {
|
|
||||||
selectedProjectId: null as string | null,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const persistOptions: PersistOptions<State, typeof stateToPersist> = {
|
|
||||||
name: "persisted-app-store",
|
|
||||||
partialize: (state) => ({
|
|
||||||
selectedProjectId: state.selectedProjectId,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
import { type StateCreator, create } from "zustand";
|
import { type StateCreator, create } from "zustand";
|
||||||
import { immer } from "zustand/middleware/immer";
|
import { immer } from "zustand/middleware/immer";
|
||||||
import { persist } from "zustand/middleware";
|
|
||||||
import { createSelectors } from "./createSelectors";
|
import { createSelectors } from "./createSelectors";
|
||||||
import {
|
import {
|
||||||
type SharedVariantEditorSlice,
|
type SharedVariantEditorSlice,
|
||||||
createVariantEditorSlice,
|
createVariantEditorSlice,
|
||||||
} from "./sharedVariantEditor.slice";
|
} from "./sharedVariantEditor.slice";
|
||||||
import { type APIClient } from "~/utils/api";
|
import { type APIClient } from "~/utils/api";
|
||||||
import { persistOptions, stateToPersist } from "./persist";
|
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
drawerOpen: boolean;
|
drawerOpen: boolean;
|
||||||
@@ -25,36 +23,30 @@ export type SliceCreator<T> = StateCreator<State, [["zustand/immer", never]], []
|
|||||||
export type SetFn = Parameters<SliceCreator<unknown>>[0];
|
export type SetFn = Parameters<SliceCreator<unknown>>[0];
|
||||||
export type GetFn = Parameters<SliceCreator<unknown>>[1];
|
export type GetFn = Parameters<SliceCreator<unknown>>[1];
|
||||||
|
|
||||||
const useBaseStore = create<
|
const useBaseStore = create<State, [["zustand/immer", never]]>(
|
||||||
State,
|
immer((set, get, ...rest) => ({
|
||||||
[["zustand/persist", typeof stateToPersist], ["zustand/immer", never]]
|
api: null,
|
||||||
>(
|
setApi: (api) =>
|
||||||
persist(
|
set((state) => {
|
||||||
immer((set, get, ...rest) => ({
|
state.api = api;
|
||||||
api: null,
|
}),
|
||||||
setApi: (api) =>
|
|
||||||
set((state) => {
|
|
||||||
state.api = api;
|
|
||||||
}),
|
|
||||||
|
|
||||||
drawerOpen: false,
|
drawerOpen: false,
|
||||||
openDrawer: () =>
|
openDrawer: () =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.drawerOpen = true;
|
state.drawerOpen = true;
|
||||||
}),
|
}),
|
||||||
closeDrawer: () =>
|
closeDrawer: () =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.drawerOpen = false;
|
state.drawerOpen = false;
|
||||||
}),
|
}),
|
||||||
sharedVariantEditor: createVariantEditorSlice(set, get, ...rest),
|
sharedVariantEditor: createVariantEditorSlice(set, get, ...rest),
|
||||||
selectedProjectId: null,
|
selectedProjectId: null,
|
||||||
setselectedProjectId: (id: string) =>
|
setselectedProjectId: (id: string) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.selectedProjectId = id;
|
state.selectedProjectId = id;
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
persistOptions,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const useAppStore = createSelectors(useBaseStore);
|
export const useAppStore = createSelectors(useBaseStore);
|
||||||
|
|||||||
Reference in New Issue
Block a user