Skip to content

Commit

Permalink
Merge pull request #261 from k35o/rounded-page
Browse files Browse the repository at this point in the history
角丸調整ページの作成
  • Loading branch information
k35o committed Sep 14, 2024
2 parents fc1dc09 + 0962a8d commit a663bb1
Show file tree
Hide file tree
Showing 26 changed files with 857 additions and 5 deletions.
10 changes: 10 additions & 0 deletions src/app/_components/app-card/app-card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { AppCard } from './app-card';
import { Link } from 'lucide-react';

const meta: Meta<typeof AppCard> = {
title: 'app/globals/app-card',
Expand All @@ -17,3 +18,12 @@ export const Primary: Story = {
description: '入力した文字列の長さをカウントします。',
},
};

export const EmotionIsElement: Story = {
args: {
link: '/characters/counter',
emotion: <Link className="size-24 text-textHighlight" />,
title: '文字数カウンター',
description: '入力した文字列の長さをカウントします。',
},
};
3 changes: 2 additions & 1 deletion src/app/_components/app-card/app-card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Route } from 'next';
import Link from 'next/link';
import { Heading } from '../../../components/heading';
import { ReactNode } from 'react';

export const AppCard = <T extends string>({
link,
Expand All @@ -9,7 +10,7 @@ export const AppCard = <T extends string>({
description,
}: {
link: Route<T>;
emotion: string;
emotion: ReactNode;
title: string;
description: string;
}) => {
Expand Down
12 changes: 12 additions & 0 deletions src/app/_styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
/* chart */
--chart-primary: 45 212 191;
--chart-empty: 243 244 246;

/* group */
--group-primary: 45 212 191;
--group-secondary: 56 189 248;
--group-tertiary: 129 140 248;
--group-quaternary: 232 121 249;
}

.dark {
Expand Down Expand Up @@ -95,6 +101,12 @@
/* chart */
--chart-primary: 94 234 212;
--chart-empty: 75 85 99;

/* group */
--group-primary: 94 234 212;
--group-secondary: 125 211 252;
--group-tertiary: 165 180 252;
--group-quaternary: 240 171 252;
}

.app-background {
Expand Down
1 change: 1 addition & 0 deletions src/app/designs/_components/rounded-icon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './rounded-icon';
12 changes: 12 additions & 0 deletions src/app/designs/_components/rounded-icon/rounded-icon.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Meta, StoryObj } from '@storybook/react';
import { RoundedIcon } from './rounded-icon';

const meta: Meta<typeof RoundedIcon> = {
title: 'app/designs/rounded-icon',
component: RoundedIcon,
};

export default meta;
type Story = StoryObj<typeof RoundedIcon>;

export const Primary: Story = {};
15 changes: 15 additions & 0 deletions src/app/designs/_components/rounded-icon/rounded-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FC } from 'react';

export const RoundedIcon: FC = () => {
return (
<div
className="h-24 w-24 bg-textHighlight"
style={{
borderBottomLeftRadius: '63% 57%',
borderBottomRightRadius: '37% 63%',
borderTopLeftRadius: '63% 43%',
borderTopRightRadius: '37%',
}}
/>
);
};
35 changes: 35 additions & 0 deletions src/app/designs/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Link from 'next/link';
import { Heading } from '@/components/heading';

export const metadata = {
title: 'Designs',
description: '自分だけのデザインを探すための場所です',
openGraph: {
title: 'Designs',
description: '自分だけのデザインを探すための場所です',
url: 'https://k8o.me/designs',
siteName: 'k8o',
locale: 'ja',
type: 'website',
},
twitter: {
title: 'Designs',
card: 'summary',
description: '自分だけのデザインを探すための場所です',
},
};

export default function Layout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex h-full flex-col gap-6">
<Link href="/number">
<Heading type="h2">Designs</Heading>
</Link>
{children}
</div>
);
}
47 changes: 47 additions & 0 deletions src/app/designs/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ImageResponse } from 'next/og';

export const runtime = 'edge';

export const alt = 'designs';
export const size = {
width: 1200,
height: 600,
};

export const contentType = 'image/png';

export default async function OpenGraphImage() {
return new ImageResponse(
(
<div
style={{
fontSize: 256,
background: '#cbd5e1',
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div
style={{
background: 'white',
width: 512,
height: 512,
display: 'flex',
borderRadius: 9999,
alignItems: 'center',
justifyContent: 'center',
}}
>
🧑‍🎨
</div>
</div>
),
{
...size,
},
);
}
15 changes: 15 additions & 0 deletions src/app/designs/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { AppCard } from '../_components/app-card';
import { RoundedIcon } from './_components/rounded-icon';

export default function Page() {
return (
<div className="flex flex-col gap-4">
<AppCard
link="/designs/rounded"
emotion={<RoundedIcon />}
title="かどまるラボ"
description="角丸を決めてお気に入りの図形を探しましょう"
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ControlPanel } from './control-panel';

const meta: Meta<typeof ControlPanel> = {
title: 'app/designs/rounded/control-panel',
component: ControlPanel,
};

export default meta;
type Story = StoryObj<typeof ControlPanel>;

export const Primary: Story = {};
189 changes: 189 additions & 0 deletions src/app/designs/rounded/_components/control-panel/control-panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
'use client';

import { FC, KeyboardEvent, MouseEvent, TouchEvent } from 'react';
import { useControlPanel } from './use-control-panel';
import clsx from 'clsx';
import { IconButton } from '@/components/icon-button';
import { ClipboardPenLine } from 'lucide-react';
import { useClipboard } from '@/hooks/clipboard';

const OperateButton: FC<{
label: string;
position: {
top?: string;
right?: string;
bottom?: string;
left?: string;
};
variable: 'primary' | 'secondary' | 'quaternary' | 'tertiary';
onMouseDown: (e: MouseEvent) => void;
onTouchStart: (e: TouchEvent) => void;
onKeyDown: (e: KeyboardEvent) => void;
isActive: boolean;
}> = ({
label,
position,
variable,
onMouseDown,
onTouchStart,
onKeyDown,
isActive,
}) => {
return (
<button
aria-label={label}
className={clsx(
'absolute size-4 border border-borderPrimary',
variable === 'primary' && 'bg-groupPrimary',
variable === 'secondary' && 'bg-groupSecondary',
variable === 'quaternary' && 'bg-groupQuaternary',
variable === 'tertiary' && 'bg-groupTertiary',
isActive &&
'border-borderTransparent outline-none ring-4 ring-textDescription',
'hover:border-borderTransparent hover:outline-none hover:ring-4 hover:ring-textDescription',
'focus-visible:border-borderTransparent focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-textDescription',
)}
onMouseDown={onMouseDown}
onTouchStart={onTouchStart}
onKeyDown={onKeyDown}
style={position}
/>
);
};

export const ControlPanel: FC = () => {
const {
activePosition,
containerRef,
mouseDownHandler,
touchStartHandler,
keyDownHandler,
borderRadius,
position,
} = useControlPanel();
const { writeClipboard } = useClipboard();

return (
<div className="flex flex-col items-center justify-center gap-8">
<div
ref={containerRef}
className="border-borderPrimar relative size-64 border-2 border-dashed sm:size-96"
>
<div
className="absolute size-full bg-textHighlight"
style={{
borderRadius,
}}
/>
<OperateButton
label="左上の上側の丸みを調整する(左右キーで操作します)"
variable="primary"
isActive={activePosition === 'topLeftX'}
onMouseDown={(e) => mouseDownHandler(e, 'topLeftX')}
onTouchStart={(e) => touchStartHandler(e, 'topLeftX')}
onKeyDown={(e) => keyDownHandler(e, 'topLeftX')}
position={{
top: '-9px',
left: `calc(${position.topLeftX}% - 9px)`,
}}
/>
<OperateButton
label="右上の上側の丸みを調整する(左右キーで操作します)"
variable="secondary"
isActive={activePosition === 'topRightX'}
onMouseDown={(e) => mouseDownHandler(e, 'topRightX')}
onTouchStart={(e) => touchStartHandler(e, 'topRightX')}
onKeyDown={(e) => keyDownHandler(e, 'topRightX')}
position={{
top: '-9px',
right: `calc(${position.topRightX}% - 9px)`,
}}
/>
<OperateButton
label="左上の左側の丸みを調整する(上下キーで操作します)"
variable="primary"
isActive={activePosition === 'topLeftY'}
onMouseDown={(e) => mouseDownHandler(e, 'topLeftY')}
onTouchStart={(e) => touchStartHandler(e, 'topLeftY')}
onKeyDown={(e) => keyDownHandler(e, 'topLeftY')}
position={{
top: `calc(${position.topLeftY}% - 9px)`,
left: '-9px',
}}
/>
<OperateButton
label="右上の右側の丸みを調整する(上下キーで操作します)"
variable="secondary"
isActive={activePosition === 'topRightY'}
onMouseDown={(e) => mouseDownHandler(e, 'topRightY')}
onTouchStart={(e) => touchStartHandler(e, 'topRightY')}
onKeyDown={(e) => keyDownHandler(e, 'topRightY')}
position={{
top: `calc(${position.topRightY}% - 9px)`,
right: '-9px',
}}
/>
<OperateButton
label="左下の左側の丸みを調整する(上下キーで操作します)"
variable="quaternary"
isActive={activePosition === 'bottomLeftY'}
onMouseDown={(e) => mouseDownHandler(e, 'bottomLeftY')}
onTouchStart={(e) => touchStartHandler(e, 'bottomLeftY')}
onKeyDown={(e) => keyDownHandler(e, 'bottomLeftY')}
position={{
bottom: `calc(${position.bottomLeftY}% - 9px)`,
left: '-9px',
}}
/>
<OperateButton
label="右下の右側の丸みを調整する(上下キーで操作します)"
variable="tertiary"
isActive={activePosition === 'bottomRightY'}
onMouseDown={(e) => mouseDownHandler(e, 'bottomRightY')}
onTouchStart={(e) => touchStartHandler(e, 'bottomRightY')}
onKeyDown={(e) => keyDownHandler(e, 'bottomRightY')}
position={{
bottom: `calc(${position.bottomRightY}% - 9px)`,
right: '-9px',
}}
/>
<OperateButton
label="左下の下側の丸みを調整する(左右キーで操作します)"
variable="quaternary"
isActive={activePosition === 'bottomLeftX'}
onMouseDown={(e) => mouseDownHandler(e, 'bottomLeftX')}
onTouchStart={(e) => touchStartHandler(e, 'bottomLeftX')}
onKeyDown={(e) => keyDownHandler(e, 'bottomLeftX')}
position={{
bottom: '-9px',
left: `calc(${position.bottomLeftX}% - 9px)`,
}}
/>
<OperateButton
label="右下の下側の丸みを調整する(左右キーで操作します)"
variable="tertiary"
isActive={activePosition === 'bottomRightX'}
onMouseDown={(e) => mouseDownHandler(e, 'bottomRightX')}
onTouchStart={(e) => touchStartHandler(e, 'bottomRightX')}
onKeyDown={(e) => keyDownHandler(e, 'bottomRightX')}
position={{
bottom: '-9px',
right: `calc(${position.bottomRightX}% - 9px)`,
}}
/>
</div>
<div className="flex flex-wrap items-center justify-center gap-4">
<p className="text-2xl font-bold">{borderRadius}</p>
<IconButton
label="値をコピーする"
bg="base"
onClick={() =>
writeClipboard(`border-radius: ${borderRadius}`)
}
>
<ClipboardPenLine className="size-6" />
</IconButton>
</div>
</div>
);
};
1 change: 1 addition & 0 deletions src/app/designs/rounded/_components/control-panel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './control-panel';
Loading

0 comments on commit a663bb1

Please sign in to comment.