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

refactor: SVGパターン画像を統一化 #33

Merged
merged 4 commits into from
Oct 21, 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
2 changes: 2 additions & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Preview, ReactRenderer, StoryContext } from "@storybook/react";
import { useEffect } from "react";
import type { DecoratorFunction } from "storybook/internal/types";
import { Background } from "~/components/Background";
import { Patterns } from "~/components/Patterns";
import { DEFAULT_THEME, THEMES, ThemeProvider } from "~/components/Theme";
import type { Theme } from "~/components/Theme";
import { appThemes } from "~/root";
Expand Down Expand Up @@ -34,6 +35,7 @@ function withProvider(): DecoratorFunction<ReactRenderer> {

return (
<ThemeProvider theme={selected}>
<Patterns />
<Background />
<Story />
</ThemeProvider>
Expand Down
63 changes: 9 additions & 54 deletions app/components/Background.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,16 @@
import type { ReactNode } from "react";
import { useEffect, useId, useRef } from "react";
import { useEffect, useRef } from "react";

import { cva } from "class-variance-authority";
import { useReducedMotion } from "~/hooks/useMedia";
import { cn } from "~/libs/utils";
import { useTheme } from "./Theme";

const bgVariants = cva("transition-color duration-300", {
variants: {
theme: {
pink: "fill-pink-400",
cyan: "fill-cyan-400",
emerald: "fill-emerald-400",
yellow: "fill-yellow-400",
},
},
});

const fgVariants = cva("transition-color duration-300", {
variants: {
theme: {
pink: "fill-pink-500/25",
cyan: "fill-cyan-500/25",
emerald: "fill-emerald-500/25",
yellow: "fill-yellow-500/25",
},
},
});
import { BACKGROUND_PATTERN_ID } from "./Patterns";

export interface BackgroundProps extends React.SVGAttributes<SVGElement> {}

export function Background({
className,
...props
}: BackgroundProps): ReactNode {
const id = useId();
const theme = useTheme();
const isReducedMotion = useReducedMotion();

const svgRef = useRef<SVGSVGElement>(null);
Expand All @@ -58,33 +33,13 @@ export function Background({
ref={svgRef}
{...props}
>
<defs>
<pattern
id={id}
width="64"
height="64"
patternUnits="userSpaceOnUse"
patternTransform="scale(2)"
>
<animateTransform
attributeType="xml"
attributeName="patternTransform"
type="translate"
from="64 0"
to="0 64"
dur="10s"
repeatCount="indefinite"
/>
<rect width="64" height="64" className={bgVariants({ theme })} />
<g className={fgVariants({ theme })}>
<polygon points="0 0 0 32 32 32 24 24 40 8 24 -8 8 8 0 0" />
<polygon points="32 32 32 64 64 64 56 56 72 40 56 24 40 40 32 32" />
<polygon points="0 32 0 48 8 40 0 32" />
<polygon points="16 64 24 56 32 64 16 64" />
</g>
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${id})`} />
<rect
x="0"
y="0"
width="100%"
height="100%"
fill={`url(#${BACKGROUND_PATTERN_ID})`}
/>
</svg>
);
}
70 changes: 4 additions & 66 deletions app/components/BottomNav.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as NavigationMenu from "@radix-ui/react-navigation-menu";
import { Link } from "@remix-run/react";
import { cva } from "class-variance-authority";
import { type ReactNode, useId } from "react";
import type { ReactNode } from "react";
import { cn } from "~/libs/utils";
import { useTheme } from "./Theme";
import { BUTTON_BG_PATTERN_ID, BUTTON_FG_PATTERN_ID } from "./Patterns";

const LINKS = [
{
Expand Down Expand Up @@ -63,69 +62,27 @@ export function BottomNav({ path, className }: BottomNavProps): ReactNode {
}

function Background(): ReactNode {
const id = useId();

return (
<svg
viewBox="0 0 382 45"
preserveAspectRatio="none"
role="presentation"
className="absolute inset-0 h-full w-full drop-shadow-lg"
>
<defs>
<pattern
id={id}
width="18"
height="36"
patternTransform="scale(.2)"
patternUnits="userSpaceOnUse"
>
<rect width="18" height="36" className="fill-zinc-600" />
<g className="fill-zinc-700/75">
<path d="M1,3h6l-3,6L1,3ZM10,21h6l-3,6-3-6Z" />
<path d="M1,3h6l-3,6L1,3ZM10,21h6l-3,6-3-6Z" />
</g>
</pattern>
</defs>
<polygon
points="17.92 0 382 7.02 368.32 40 0 45 17.92 0"
fill={`url(#${id})`}
fill={`url(#${BUTTON_BG_PATTERN_ID})`}
/>
</svg>
);
}

const patternBgVariant = cva("transition-color duration-300", {
variants: {
theme: {
pink: "fill-pink-400",
cyan: "fill-cyan-400",
emerald: "fill-emerald-400",
yellow: "fill-yellow-400",
},
},
});

const patternFgVariant = cva("transition-color duration-300", {
variants: {
theme: {
pink: "fill-pink-500/50",
cyan: "fill-cyan-500/50",
emerald: "fill-emerald-500/50",
yellow: "fill-yellow-500/50",
},
},
});

interface SelectedProps {
length: number;
index: number;
}

function Selected({ length, index }: SelectedProps): ReactNode {
const id = useId();
const theme = useTheme();

return (
<div className="absolute inset-x-4 inset-y-0">
<div
Expand All @@ -141,31 +98,12 @@ function Selected({ length, index }: SelectedProps): ReactNode {
role="presentation"
className="md:-skew-y-3 -skew-y-6 skew-x-12 p-1 drop-shadow-md md:px-4"
>
<defs>
<pattern
id={id}
width="32"
height="32"
patternTransform="scale(0.3)"
patternUnits="userSpaceOnUse"
>
<rect
width="32"
height="32"
className={patternBgVariant({ theme })}
/>
<path
d="M20 20c0-2.21 1.79-4 4-4s4 1.79 4 4-1.79 4-4 4c0 2.21-1.79 4-4 4s-4-1.79-4-4 1.79-4 4-4ZM4 4c0-2.21 1.79-4 4-4s4 1.79 4 4-1.79 4-4 4c0 2.21-1.79 4-4 4s-4-1.79-4-4 1.79-4 4-4Zm4 3.2c1.77 0 3.2-1.43 3.2-3.2S9.77.8 8 .8 4.8 2.23 4.8 4 6.23 7.2 8 7.2Zm16 16c1.77 0 3.2-1.43 3.2-3.2s-1.43-3.2-3.2-3.2-3.2 1.43-3.2 3.2 1.43 3.2 3.2 3.2Z"
className={patternFgVariant({ theme })}
/>
</pattern>
</defs>
<rect
x="0"
y="0"
width="100%"
height="100%"
fill={`url(#${id})`}
fill={`url(#${BUTTON_FG_PATTERN_ID})`}
className="stroke-white"
strokeWidth="5"
/>
Expand Down
81 changes: 38 additions & 43 deletions app/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,54 @@
import { Slot } from "@radix-ui/react-slot";
import { cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import * as React from "react";

import { cn } from "~/libs/utils";
import { useTheme } from "./Theme";

const buttonThemeVariants = cva(
"absolute inset-0 skew-x-12 -skew-y-3 border-2 border-white bg-size-button",
{
variants: {
theme: {
pink: "bg-button-pink bg-pink-400",
cyan: "bg-button-cyan bg-cyan-400",
emerald: "bg-button-emerald bg-emerald-400",
yellow: "bg-button-yellow bg-yellow-400",
},
},
defaultVariants: {
theme: "pink",
},
},
);

const buttonBgVariants = cva(
"-skew-x-12 skew-y-6 absolute inset-0 bg-button-bg bg-size-button-bg bg-zinc-600",
{
variants: {
background: {
true: "",
false: "hidden",
},
},
defaultVariants: {
background: true,
},
},
);
import { BUTTON_BG_PATTERN_ID, BUTTON_FG_PATTERN_ID } from "./Patterns";

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonBgVariants> {
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
background?: boolean;
asChild?: boolean;
}

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, asChild = false, children, background, ...props }, ref) => {
const theme = useTheme();

(
{ className, background = true, asChild = false, children, ...props },
ref,
) => {
const Comp = asChild ? Slot : "button";
return (
<Comp className={cn("relative px-5 py-2")} ref={ref} {...props}>
<Comp className={cn("group relative px-5 py-2")} ref={ref} {...props}>
<div className="absolute inset-0 drop-shadow-md">
<span className={buttonBgVariants({ background })} />
<span className={buttonThemeVariants({ theme })} />
{background && (
<svg
className={cn(
"-skew-x-12 absolute inset-0 h-full w-full rotate-6 transition-transform duration-300 group-hover:rotate-1",
)}
role="presentation"
>
<rect
x="0"
y="0"
width="100%"
height="100%"
fill={`url(#${BUTTON_BG_PATTERN_ID})`}
/>
</svg>
)}
<svg
className={cn(
"-rotate-3 group-hover:-rotate-1 absolute inset-0 h-full w-full skew-x-12 border-2 border-white transition-transform duration-300",
)}
role="presentation"
>
<rect
x="0"
y="0"
width="100%"
height="100%"
fill={`url(#${BUTTON_FG_PATTERN_ID})`}
/>
</svg>
</div>
<span className="drop-shadow-base">{children}</span>
</Comp>
Expand Down
Loading