Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: login and signup page design #203

Merged
merged 4 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions pkgs/frontend/app/components/BasicButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import CommonButton from "./common/CommonButton";

interface BasicButtonProps extends React.ComponentProps<typeof CommonButton> {
children: React.ReactNode;
}

export const BasicButton = ({ children, ...props }: BasicButtonProps) => {
return (
<CommonButton
size="lg"
h="40px"
maxHeight="64px"
minHeight="48px"
{...props}
>
{children}
</CommonButton>
);
};
70 changes: 32 additions & 38 deletions pkgs/frontend/app/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { useState, useEffect } from "react";
import { Box, Text } from "@chakra-ui/react";
import { WorkspaceIcon } from "./WorkspaceIcon";
import { UserIcon } from "./UserIcon";
import { Box, Flex, Text } from "@chakra-ui/react";
import { WorkspaceIcon } from "./icon/WorkspaceIcon";
import { UserIcon } from "./icon/UserIcon";
import { useLocation } from "@remix-run/react";

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

const headerTextStyle = {
color: "gray.800",
my: "auto",
wordBreak: "break-word",
flex: "1",
Expand Down Expand Up @@ -43,7 +45,8 @@ export const Header = () => {
isWalletConnected &&
isUserTobanEnsFound
) {
return isWorkspaceSelected && workspaceName
return !WORKSPACES_PATHS.includes(pathname) ||
(isWorkspaceSelected && workspaceName)
? HeaderType.WorkspaceAndUserIcons
: HeaderType.UserIconOnly;
}
Expand All @@ -59,38 +62,29 @@ export const Header = () => {
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>
return headerType !== HeaderType.NonHeader ? (
<Flex justifyContent="space-between" w="100%">
<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} />
</Flex>
) : (
<></>
);
};
21 changes: 0 additions & 21 deletions pkgs/frontend/app/components/UserIcon.tsx

This file was deleted.

5 changes: 3 additions & 2 deletions pkgs/frontend/app/components/common/CommonButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export const CommonButton = ({
children,
width = "full",
size = "md",
backgroundColor,
color,
backgroundColor = "yellow.400",
color = "gray.800",
...props
}: CommonButtonProps) => {
return (
Expand All @@ -22,6 +22,7 @@ export const CommonButton = ({
size={size}
backgroundColor={backgroundColor}
color={color}
borderRadius="12px"
{...props}
>
{children}
Expand Down
4 changes: 3 additions & 1 deletion pkgs/frontend/app/components/common/CommonIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Box, Image } from "@chakra-ui/react";

interface CommonIconProps {
imageUrl: string | undefined;
size: number;
size: number | "full";
fallbackIconComponent?: ReactNode;
}

Expand All @@ -28,13 +28,15 @@ export const CommonIcon = ({
my="auto"
borderRadius="full"
flexShrink={0}
overflow="hidden"
>
{!showFallbackIcon ? (
<Image
src={imageUrl}
width="100%"
height="100%"
objectFit="cover"
borderRadius="full"
onError={() => setShowFallbackIcon(true)}
/>
) : (
Expand Down
16 changes: 14 additions & 2 deletions pkgs/frontend/app/components/common/CommonInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ interface CommonInputProps extends Omit<InputProps, "value"> {
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}

export const CommonInput = ({ value, onChange }: CommonInputProps) => {
return <Input value={value} onChange={onChange} />;
export const CommonInput = ({
value,
placeholder,
onChange,
}: CommonInputProps) => {
return (
<Input
value={value}
placeholder={placeholder}
width="100%"
onChange={onChange}
borderColor="gray.800"
/>
);
};
28 changes: 28 additions & 0 deletions pkgs/frontend/app/components/icon/UserIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FaCircleUser } from "react-icons/fa6";
import { CommonIcon } from "../common/CommonIcon";

interface UserIconProps {
userImageUrl: string | undefined;
size?: number | "full";
}

export const UserIcon = ({ userImageUrl, size = "full" }: UserIconProps) => {
return (
<CommonIcon
imageUrl={userImageUrl}
size={size}
fallbackIconComponent={
<FaCircleUser
style={{
color: "#e9ecef",
width: "100%",
height: "100%",
objectFit: "cover",
borderRadius: "100%",
border: "1px solid #343a40",
}}
/>
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { FaPeopleGroup } from "react-icons/fa6";
import { CommonIcon } from "./common/CommonIcon";
import { CommonIcon } from "../common/CommonIcon";

interface WorkspaceIconProps {
workspaceImageUrl?: string;
size: number;
size?: number | "full";
}

export const WorkspaceIcon = ({
workspaceImageUrl,
size,
size = "full",
}: WorkspaceIconProps) => {
return (
<CommonIcon
Expand Down
32 changes: 29 additions & 3 deletions pkgs/frontend/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,36 @@ export const Layout = withEmotionCache((props: LayoutProps, cache) => {
/>
</head>
<body>
<Box bg="gray.50" minHeight="100vh" overflow="auto">
<Container bg="white" maxW="430px" minH="100vh" px={5} py={4}>
<Box
bg="gray.50"
width="100%"
height="100vh"
display="flex"
justifyContent="center"
overflow="auto"
>
<Container
bg="#fffdf8"
maxW="430px"
height="100%"
width="100%"
px={5}
py={4}
display="flex"
flexDirection="column"
alignItems="center"
position="relative"
>
<Header />
{children}
<Box
width="100%"
height="100%"
display="flex"
flexDirection="column"
position="relative"
>
{children}
</Box>
</Container>
</Box>
<ScrollRestoration />
Expand Down
52 changes: 52 additions & 0 deletions pkgs/frontend/app/routes/api.namestone.$action.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ActionFunction, LoaderFunction } from "@remix-run/node";
import NameStone, { NameData } from "namestone-sdk";

const ns = new NameStone(import.meta.env.VITE_NAMESTONE_API_KEY);
const domain = "toban.eth";

export const loader: LoaderFunction = async ({ request, params }) => {
const { action } = params;

switch (action) {
case "resolve-names":
const addresses = new URL(request.url).searchParams.get("addresses");
if (!addresses) return Response.json([]);

const resolvedNames = await Promise.all(
addresses.split(",").map((address) => ns.getNames({ domain, address }))
);
return Response.json(resolvedNames);
case "resolve-addresses":
const names = new URL(request.url).searchParams.get("names");
if (!names) return Response.json([]);

const resolvedAddresses = await Promise.all(
names
.split(",")
.map((name) =>
ns.searchNames({ domain, name, exact_match: 1 as any })
)
);
return Response.json(resolvedAddresses);
default:
throw Response.json({ message: "Not Found" }, { status: 404 });
}
};

export const action: ActionFunction = async ({ request, params }) => {
const { method } = request;
const { action } = params;

if (method === "POST") {
switch (action) {
case "set-name":
const { name, address, text_records } = await request.json();
await ns.setName({ domain, name, address, text_records });
return Response.json({ message: "OK" });
default:
throw Response.json({ message: "Not Found" }, { status: 404 });
}
}

throw Response.json({ message: "Not Found" }, { status: 404 });
};
Loading
Loading