-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #196 from hackdays-io/feature/header
Feature/header
- Loading branch information
Showing
16 changed files
with
2,309 additions
and
2,112 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { useState, useEffect } from "react"; | ||
import { Box, Text } from "@chakra-ui/react"; | ||
import { WorkspaceIcon } from "./WorkspaceIcon"; | ||
import { UserIcon } from "./UserIcon"; | ||
import { useLocation } from "@remix-run/react"; | ||
|
||
const NO_HEADER_PATHS: string[] = ["/login"]; // 適宜ヘッダーが不要なページのパスを追加 | ||
const HEADER_SIZE: number = 12; // 偶数のnumberだとアイコンが対応しているため望ましい | ||
|
||
const headerTextStyle = { | ||
my: "auto", | ||
wordBreak: "break-word", | ||
flex: "1", | ||
}; | ||
|
||
enum HeaderType { | ||
NonHeader = "NonHeader", | ||
UserIconOnly = "UserIconOnly", | ||
WorkspaceAndUserIcons = "WorkspaceAndUserIcons", | ||
} | ||
|
||
export const Header = () => { | ||
const [headerType, setHeaderType] = useState<HeaderType>( | ||
HeaderType.NonHeader | ||
); | ||
|
||
const { pathname } = useLocation(); | ||
|
||
// ToDo: ページのパスや hooks で柔軟にロジックを実装する(切り替えてテストできます) | ||
const isWalletConnected = true; | ||
const isUserTobanEnsFound = true; | ||
const isWorkspaceSelected = true; | ||
|
||
// ToDo: ユーザーやワークスペースごとの各種データを取得するロジックを実装する | ||
const userImageUrl: string | undefined = undefined; | ||
const workspaceName: string | undefined = "Workspace Name"; | ||
const workspaceImageUrl: string | undefined = undefined; | ||
|
||
useEffect(() => { | ||
const determineHeaderType = () => { | ||
if ( | ||
!NO_HEADER_PATHS.includes(pathname) && | ||
isWalletConnected && | ||
isUserTobanEnsFound | ||
) { | ||
return isWorkspaceSelected && workspaceName | ||
? HeaderType.WorkspaceAndUserIcons | ||
: HeaderType.UserIconOnly; | ||
} | ||
return HeaderType.NonHeader; | ||
}; | ||
|
||
setHeaderType(determineHeaderType()); | ||
}, [ | ||
pathname, | ||
isWalletConnected, | ||
isUserTobanEnsFound, | ||
isWorkspaceSelected, | ||
workspaceName, | ||
]); | ||
|
||
return ( | ||
<Box | ||
height={HEADER_SIZE} | ||
display="flex" | ||
justifyContent="space-between" | ||
width="100%" | ||
alignItems="center" | ||
mb={6} | ||
> | ||
{headerType !== HeaderType.NonHeader && ( | ||
<> | ||
<Box display="flex" height={HEADER_SIZE} flex="1"> | ||
{headerType === HeaderType.UserIconOnly && ( | ||
<Text {...headerTextStyle} fontSize="xl"> | ||
Workspaces | ||
</Text> | ||
)} | ||
{headerType === HeaderType.WorkspaceAndUserIcons && ( | ||
<> | ||
<WorkspaceIcon | ||
workspaceImageUrl={workspaceImageUrl} | ||
size={HEADER_SIZE} | ||
/> | ||
<Text {...headerTextStyle} ml={4}> | ||
{workspaceName} | ||
</Text> | ||
</> | ||
)} | ||
</Box> | ||
<UserIcon userImageUrl={userImageUrl} size={HEADER_SIZE - 2} /> | ||
</> | ||
)} | ||
</Box> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { FaCircleUser } from "react-icons/fa6"; | ||
import { CommonIcon } from "./common/CommonIcon"; | ||
|
||
interface UserIconProps { | ||
userImageUrl: string | undefined; | ||
size: number; | ||
} | ||
|
||
export const UserIcon = ({ userImageUrl, size }: UserIconProps) => { | ||
return ( | ||
<CommonIcon | ||
imageUrl={userImageUrl} | ||
size={size} | ||
fallbackIconComponent={ | ||
<FaCircleUser | ||
style={{ width: "100%", height: "100%", objectFit: "cover" }} | ||
/> | ||
} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { FaPeopleGroup } from "react-icons/fa6"; | ||
import { CommonIcon } from "./common/CommonIcon"; | ||
|
||
interface WorkspaceIconProps { | ||
workspaceImageUrl?: string; | ||
size: number; | ||
} | ||
|
||
export const WorkspaceIcon = ({ | ||
workspaceImageUrl, | ||
size, | ||
}: WorkspaceIconProps) => { | ||
return ( | ||
<CommonIcon | ||
imageUrl={workspaceImageUrl} | ||
size={size} | ||
fallbackIconComponent={ | ||
<FaPeopleGroup | ||
style={{ | ||
width: "90%", | ||
height: "90%", | ||
objectFit: "cover", | ||
}} | ||
/> | ||
} | ||
/> | ||
); | ||
}; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { | ||
DialogContent, | ||
DialogRoot, | ||
DialogTrigger, | ||
} from "~/components/ui/dialog"; | ||
|
||
interface CommonDialogProps { | ||
dialogTriggerReactNode?: React.ReactNode; | ||
children?: React.ReactNode; | ||
} | ||
|
||
export const CommonDialog = ({ | ||
dialogTriggerReactNode, | ||
children, | ||
}: CommonDialogProps) => { | ||
return ( | ||
<DialogRoot> | ||
<DialogTrigger asChild>{dialogTriggerReactNode}</DialogTrigger> | ||
<DialogContent>{children}</DialogContent> | ||
</DialogRoot> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { useState, useEffect, ReactNode } from "react"; | ||
import { Box, Image } from "@chakra-ui/react"; | ||
|
||
interface CommonIconProps { | ||
imageUrl: string | undefined; | ||
size: number; | ||
fallbackIconComponent?: ReactNode; | ||
} | ||
|
||
export const CommonIcon = ({ | ||
size, | ||
imageUrl, | ||
fallbackIconComponent, | ||
}: CommonIconProps) => { | ||
const [showFallbackIcon, setShowFallbackIcon] = useState(!imageUrl); | ||
|
||
useEffect(() => { | ||
setShowFallbackIcon(!imageUrl); | ||
}, [imageUrl]); | ||
|
||
return ( | ||
<Box | ||
height={size} | ||
width={size} | ||
display="flex" | ||
alignItems="center" | ||
justifyContent="center" | ||
my="auto" | ||
borderRadius="full" | ||
flexShrink={0} | ||
> | ||
{!showFallbackIcon ? ( | ||
<Image | ||
src={imageUrl} | ||
width="100%" | ||
height="100%" | ||
objectFit="cover" | ||
onError={() => setShowFallbackIcon(true)} | ||
/> | ||
) : ( | ||
fallbackIconComponent || null | ||
)} | ||
</Box> | ||
); | ||
}; |
6 changes: 3 additions & 3 deletions
6
pkgs/frontend/app/components/CommonInput.tsx → ...end/app/components/common/CommonInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
import { Input, InputProps } from "@chakra-ui/react"; | ||
|
||
interface CommonInputProps extends Omit<InputProps, "value"> { | ||
value: string | number; | ||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void; | ||
value: string | number; | ||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void; | ||
} | ||
|
||
export const CommonInput = ({ value, onChange }: CommonInputProps) => { | ||
return <Input value={value} onChange={onChange} />; | ||
return <Input value={value} onChange={onChange} />; | ||
}; |
6 changes: 3 additions & 3 deletions
6
...rontend/app/components/CommonTextarea.tsx → .../app/components/common/CommonTextarea.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
import { Textarea, TextareaProps } from "@chakra-ui/react"; | ||
|
||
interface CommonTextAreaProps extends Omit<TextareaProps, "value"> { | ||
value: string; | ||
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void; | ||
value: string; | ||
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void; | ||
} | ||
|
||
export const CommonTextArea = ({ value, onChange }: CommonTextAreaProps) => { | ||
return <Textarea value={value} onChange={onChange} />; | ||
return <Textarea value={value} onChange={onChange} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,66 @@ | ||
import { withEmotionCache } from "@emotion/react"; | ||
import { | ||
Links, | ||
Meta, | ||
Outlet, | ||
Scripts, | ||
ScrollRestoration, | ||
Links, | ||
Meta, | ||
Outlet, | ||
Scripts, | ||
ScrollRestoration, | ||
} from "@remix-run/react"; | ||
import { ThemeProvider } from "next-themes"; | ||
// import { ThemeProvider } from "next-themes"; // DarkMode 切り替えの実装の可能性に備え、ThemeProvider を残しておいてあります | ||
import { ChakraProvider } from "./components/chakra-provider"; | ||
import { useInjectStyles } from "./emotion/emotion-client"; | ||
import { PrivyProvider } from "@privy-io/react-auth"; | ||
|
||
import { Box, Container } from "@chakra-ui/react"; | ||
import { Header } from "./components/Header"; | ||
interface LayoutProps extends React.PropsWithChildren {} | ||
|
||
export const Layout = withEmotionCache((props: LayoutProps, cache) => { | ||
const { children } = props; | ||
const { children } = props; | ||
|
||
useInjectStyles(cache); | ||
useInjectStyles(cache); | ||
|
||
return ( | ||
<html lang="en"> | ||
<head suppressHydrationWarning> | ||
<meta charSet="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<Meta /> | ||
<Links /> | ||
<meta | ||
name="emotion-insertion-point" | ||
content="emotion-insertion-point" | ||
/> | ||
</head> | ||
<body> | ||
{children} | ||
<ScrollRestoration /> | ||
<Scripts /> | ||
</body> | ||
</html> | ||
); | ||
return ( | ||
<html lang="en"> | ||
<head suppressHydrationWarning> | ||
<meta charSet="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<Meta /> | ||
<Links /> | ||
<meta | ||
name="emotion-insertion-point" | ||
content="emotion-insertion-point" | ||
/> | ||
</head> | ||
<body> | ||
<Box bg="gray.50" minHeight="100vh" overflow="auto"> | ||
<Container bg="white" maxW="430px" minH="100vh" px={5} py={4}> | ||
<Header /> | ||
{children} | ||
</Container> | ||
</Box> | ||
<ScrollRestoration /> | ||
<Scripts /> | ||
</body> | ||
</html> | ||
); | ||
}); | ||
|
||
export default function App() { | ||
return ( | ||
<PrivyProvider | ||
appId={import.meta.env.VITE_PRIVY_APP_ID} | ||
config={{ | ||
embeddedWallets: { | ||
createOnLogin: "users-without-wallets", | ||
}, | ||
}} | ||
> | ||
<ChakraProvider> | ||
<ThemeProvider disableTransitionOnChange attribute="class"> | ||
<Outlet /> | ||
</ThemeProvider> | ||
</ChakraProvider> | ||
</PrivyProvider> | ||
); | ||
return ( | ||
<PrivyProvider | ||
appId={import.meta.env.VITE_PRIVY_APP_ID} | ||
config={{ | ||
embeddedWallets: { | ||
createOnLogin: "users-without-wallets", | ||
}, | ||
}} | ||
> | ||
<ChakraProvider> | ||
{/* DarkMode 切り替えの実装の可能性に備え、ThemeProvider を残しておいてあります */} | ||
{/* <ThemeProvider disableTransitionOnChange attribute="class"> */} | ||
<Outlet /> | ||
{/* </ThemeProvider> */} | ||
</ChakraProvider> | ||
</PrivyProvider> | ||
); | ||
} |
Oops, something went wrong.