Skip to content

Commit

Permalink
Merge pull request #230 from hackdays-io/feature/navigation
Browse files Browse the repository at this point in the history
Add sticky nav
  • Loading branch information
yu23ki14 authored Dec 31, 2024
2 parents 3851ffe + a1b5277 commit 23666ba
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 91 deletions.
68 changes: 36 additions & 32 deletions pkgs/frontend/app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import { useState, useEffect, useMemo } from "react";
import { Box, Flex, Text } from "@chakra-ui/react";
import { WorkspaceIcon } from "./icon/WorkspaceIcon";
import { UserIcon } from "./icon/UserIcon";
import { useLocation, useNavigate } from "@remix-run/react";
import { Link, useLocation, useNavigate, useParams } from "@remix-run/react";
import { useActiveWalletIdentity } from "hooks/useENS";
import { ipfs2https } from "utils/ipfs";
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from "./ui/menu";
import { useActiveWallet } from "hooks/useWallet";
import { usePrivy, useWallets } from "@privy-io/react-auth";
import CommonButton from "./common/CommonButton";
import { useTreeInfo } from "hooks/useHats";
import axios from "axios";
import { HatsDetailSchama } from "types/hats";

const NO_HEADER_PATHS: string[] = ["/login", "/signup"]; // 適宜ヘッダーが不要なページのパスを追加
const WORKSPACES_PATHS: string[] = ["/workspace", "/workspace/new"]; // 適宜ワークスペースが未選択な状態のページのパスを追加
const HEADER_SIZE: number = 12; // 偶数のnumberだとアイコンが対応しているため望ましい

const headerTextStyle = {
color: "gray.800",
Expand All @@ -34,39 +36,36 @@ export const Header = () => {

const navigate = useNavigate();
const { pathname } = useLocation();
const { treeId } = useParams();
const treeInfo = useTreeInfo(Number(treeId));

// ToDo: ページのパスや hooks で柔軟にロジックを実装する(切り替えてテストできます)
const isWalletConnected = true;
const isUserTobanEnsFound = true;
const isWorkspaceSelected = false;

// ToDo: ユーザーやワークスペースごとの各種データを取得するロジックを実装する
const workspaceName: string | undefined = "Workspace Name";
const workspaceImageUrl: string | undefined = undefined;
const [workspaceName, setWorkspaceName] = useState<string>();
useEffect(() => {
const fetch = async () => {
setWorkspaceName(undefined);
const topHat = treeInfo?.hats?.find((hat) => hat.levelAtLocalTree === 0);
if (topHat) {
const { data } = await axios.get<HatsDetailSchama>(
ipfs2https(topHat.details)!
);
setWorkspaceName(data.data.name);
}
};
fetch();
}, [treeInfo]);

useEffect(() => {
const determineHeaderType = () => {
if (
!NO_HEADER_PATHS.includes(pathname) &&
isWalletConnected &&
isUserTobanEnsFound
) {
return !WORKSPACES_PATHS.includes(pathname) ||
(isWorkspaceSelected && workspaceName)
if (!NO_HEADER_PATHS.includes(pathname)) {
return !WORKSPACES_PATHS.includes(pathname) || workspaceName
? HeaderType.WorkspaceAndUserIcons
: HeaderType.UserIconOnly;
}
return HeaderType.NonHeader;
};

setHeaderType(determineHeaderType());
}, [
pathname,
isWalletConnected,
isUserTobanEnsFound,
isWorkspaceSelected,
workspaceName,
]);
}, [pathname, workspaceName]);

const { isSmartWallet } = useActiveWallet();
const { logout } = usePrivy();
Expand All @@ -92,19 +91,24 @@ export const Header = () => {

return headerType !== HeaderType.NonHeader ? (
<Flex justifyContent="space-between" w="100%">
<Box display="flex" height={HEADER_SIZE} flex="1">
<Box display="flex" height="48px" flex="1">
{headerType === HeaderType.UserIconOnly && (
<Text {...headerTextStyle} fontSize="xl">
<Text {...headerTextStyle} fontSize="xl" fontWeight="bold">
Workspaces
</Text>
)}
{headerType === HeaderType.WorkspaceAndUserIcons && (
<>
<WorkspaceIcon
workspaceImageUrl={workspaceImageUrl}
size={HEADER_SIZE}
/>
<Text {...headerTextStyle} ml={4}>
<Link to="/workspace">
<WorkspaceIcon
workspaceImageUrl={ipfs2https(
treeInfo?.hats?.find((hat) => hat.levelAtLocalTree === 0)
?.imageUri
)}
size="55px"
/>
</Link>
<Text fontSize="xl" fontWeight="bold" {...headerTextStyle} ml={4}>
{workspaceName}
</Text>
</>
Expand All @@ -114,7 +118,7 @@ export const Header = () => {
<MenuRoot closeOnSelect={false}>
<MenuTrigger asChild>
<button>
<UserIcon userImageUrl={userImageUrl} size={HEADER_SIZE - 2} />
<UserIcon userImageUrl={userImageUrl} size="40px" />
</button>
</MenuTrigger>
<MenuContent>
Expand Down
74 changes: 74 additions & 0 deletions pkgs/frontend/app/components/StickyNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Box, Grid, GridItem, Icon, IconButton } from "@chakra-ui/react";
import { Link, useParams } from "@remix-run/react";
import { FC } from "react";
import { GoHomeFill } from "react-icons/go";
import { MdCallSplit } from "react-icons/md";
import { RiTeamFill } from "react-icons/ri";

export const StickyNav: FC = () => {
const { treeId } = useParams();
return (
<>
<Box w="100%" h="80px" />
<Box
position="fixed"
bottom={0}
left={0}
bg="offwhite.400"
color="blue.500"
width="100%"
zIndex={100}
>
<Grid
gridTemplateColumns="1fr 1fr 1fr"
maxW="430px"
width="100%"
m="0 auto"
borderTop="3px solid"
borderColor="blackAlpha.200"
py={2}
bg="#fffdf8"
>
<GridItem textAlign="center">
<Link to={`/${treeId}`}>
<IconButton backgroundColor="transparent" color="blue.500">
<Icon fontSize={30}>
<GoHomeFill />
</Icon>
</IconButton>
<Box fontWeight="bold" fontSize="sm">
Home
</Box>
</Link>
</GridItem>

<GridItem textAlign="center">
<Link to={`/${treeId}/member`}>
<IconButton backgroundColor="transparent" color="blue.500">
<Icon fontSize={30}>
<RiTeamFill />
</Icon>
</IconButton>
<Box fontWeight="bold" fontSize="sm">
Member
</Box>
</Link>
</GridItem>

<GridItem textAlign="center">
<Link to={`/${treeId}/splits`}>
<IconButton backgroundColor="transparent" color="blue.500">
<Icon fontSize={30}>
<MdCallSplit size="30px" />
</Icon>
</IconButton>
<Box fontWeight="bold" fontSize="sm">
Splits
</Box>
</Link>
</GridItem>
</Grid>
</Box>
</>
);
};
14 changes: 5 additions & 9 deletions pkgs/frontend/app/components/icon/WorkspaceIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { FaPeopleGroup } from "react-icons/fa6";
import { CommonIcon } from "../common/CommonIcon";
import { Icon } from "@chakra-ui/react";

interface WorkspaceIconProps {
workspaceImageUrl?: string | undefined;
size?: number | "full";
size?: `${number}px` | number | "full";
}

export const WorkspaceIcon = ({
Expand All @@ -16,14 +17,9 @@ export const WorkspaceIcon = ({
size={size}
borderRadius="xl"
fallbackIconComponent={
<FaPeopleGroup
style={{
width: "90%",
height: "90%",
objectFit: "cover",
backgroundColor: "yellow",
}}
/>
<Icon fontSize={size} bgColor="yellow.200" p={2}>
<FaPeopleGroup />
</Icon>
}
/>
);
Expand Down
2 changes: 2 additions & 0 deletions pkgs/frontend/app/routes/$treeId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MyRole } from "~/components/roles/MyRole";
import { CommonButton } from "~/components/common/CommonButton";
import { HatsListItemParser } from "~/components/common/HatsListItemParser";
import { VRole } from "~/components/roles/VRole";
import { StickyNav } from "~/components/StickyNav";

const WorkspaceTop: FC = () => {
const { wallet } = useActiveWallet();
Expand Down Expand Up @@ -73,6 +74,7 @@ const WorkspaceTop: FC = () => {
</VStack>
</SimpleGrid>
</Box>
<StickyNav />
</>
);
};
Expand Down
3 changes: 3 additions & 0 deletions pkgs/frontend/app/routes/$treeId_.member.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ipfs2https } from "utils/ipfs";
import { HatsListItemParser } from "~/components/common/HatsListItemParser";
import { UserIcon } from "~/components/icon/UserIcon";
import { RoleTag } from "~/components/roles/RoleTag";
import { StickyNav } from "~/components/StickyNav";

const WorkspaceMember: FC = () => {
const { treeId } = useParams();
Expand Down Expand Up @@ -166,6 +167,8 @@ const WorkspaceMember: FC = () => {
<Heading p={4}>Contribution</Heading>
{/* 何らかの形でコントリビューションのランクを出したい */}
</Box>

<StickyNav />
</>
);
};
Expand Down
54 changes: 29 additions & 25 deletions pkgs/frontend/app/routes/$treeId_.splits._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { abbreviateAddress } from "utils/wallet";
import { currentChain, publicClient } from "hooks/useViem";
import dayjs from "dayjs";
import { SplitRecipientsList } from "~/components/splits/SplitRecipientsList";
import { StickyNav } from "~/components/StickyNav";

interface SplitInfoItemProps {
split: Split;
Expand Down Expand Up @@ -147,31 +148,34 @@ const SplitsIndex: FC = () => {
useSplitsCreatorRelatedSplits(splitCreatorAddress);

return (
<Box w="100%">
<Flex my={4} placeItems="center">
<Text fontSize="lg" flexGrow={1}>
Splits
</Text>
<Link to={`/${treeId}/splits/new`}>
<CommonButton w={"auto"} size="sm">
Create New
</CommonButton>
</Link>
</Flex>

{isLoading ? (
<></>
) : (
<VStack gap={3} mb={10}>
{splits
.slice()
.sort((a, b) => Number(b.createdBlock) - Number(a.createdBlock))
.map((split) => (
<SplitInfoItem key={split.address} split={split} />
))}
</VStack>
)}
</Box>
<>
<Box w="100%">
<Flex my={4} placeItems="center">
<Text fontSize="lg" flexGrow={1}>
Splits
</Text>
<Link to={`/${treeId}/splits/new`}>
<CommonButton w={"auto"} size="sm">
Create New
</CommonButton>
</Link>
</Flex>

{isLoading ? (
<></>
) : (
<VStack gap={3} mb={10}>
{splits
.slice()
.sort((a, b) => Number(b.createdBlock) - Number(a.createdBlock))
.map((split) => (
<SplitInfoItem key={split.address} split={split} />
))}
</VStack>
)}
</Box>
<StickyNav />
</>
);
};

Expand Down
34 changes: 17 additions & 17 deletions pkgs/frontend/app/routes/workspace._index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { FC, useEffect, useMemo, useRef, useState } from "react";
import { FC, useEffect, useMemo, useState } from "react";
import { Box, Text } from "@chakra-ui/react";
import { WorkspaceIcon } from "~/components/icon/WorkspaceIcon";
import { BasicButton } from "~/components/BasicButton";
import { useNavigate } from "@remix-run/react";
import { Link, useNavigate } from "@remix-run/react";
import { useActiveWallet } from "hooks/useWallet";
import { useHats } from "../../hooks/useHats";
import { Address } from "viem";
Expand All @@ -12,22 +12,22 @@ const WorkspaceCard: FC<{
name: string;
imageUrl: string | undefined;
}> = ({ treeId, name, imageUrl }) => {
const navigate = useNavigate();

return (
<Box
w="100%"
borderRadius="xl"
border="1px solid #E0E0E0"
mb={3}
p={3}
display="flex"
alignItems="center"
onClick={() => navigate(`/${treeId}`)}
>
<WorkspaceIcon workspaceImageUrl={imageUrl} size={12} />
<Text ml={4}>{name}</Text>
</Box>
<Link to={`/${treeId}`}>
<Box
w="100%"
borderRadius="xl"
border="1px solid #E0E0E0"
mb={3}
p={2}
display="flex"
alignItems="center"
bgColor="blue.100"
>
<WorkspaceIcon workspaceImageUrl={imageUrl} size="60px" />
<Text ml={4}>{name}</Text>
</Box>
</Link>
);
};

Expand Down
4 changes: 2 additions & 2 deletions pkgs/frontend/hooks/useENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const useActiveWalletIdentity = () => {
const { names } = useNamesByAddresses(address);

const identity = useMemo(() => {
if (!names || names.length === 0) return;
if (!wallet || !names || names.length === 0) return;
return names[0][0];
}, [names]);
}, [names, wallet]);

return { identity };
};
Expand Down
Loading

0 comments on commit 23666ba

Please sign in to comment.