Skip to content

Commit

Permalink
feat: add temporal controls to skeleton
Browse files Browse the repository at this point in the history
  • Loading branch information
malangcat committed Sep 4, 2024
1 parent f2e0fb1 commit cf8d15d
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import * as React from "react";

import Layout from "@/activities/ActivityLayout";
import { Skeleton } from "@/seed-design/ui/skeleton";
import { useSkeletonLoading } from "@/stores/skeleton";
import { useSkeletonDuration, useSkeletonLoading } from "@/stores/skeleton";

declare module "@stackflow/config" {
interface Register {
SkeletonPulse: unknown;
SkeletonWave: unknown;
}
}

Expand All @@ -24,16 +24,26 @@ const Fallback = () => {
);
};

const SkeletonPulseActivitiy: ActivityComponentType<"SkeletonPulse"> = () => {
const SkeletonWaveActivity: ActivityComponentType<"SkeletonWave"> = () => {
const isLoading = useSkeletonLoading();
const animationDuration = useSkeletonDuration();

return (
<Layout>
<div style={{ padding: "16px" }}>{isLoading ? <Fallback /> : <div>content</div>}</div>
<div
style={
{
padding: "16px",
"--skeleton-animation-duration": animationDuration,
} as React.CSSProperties
}
>
{isLoading ? <Fallback /> : <div>content</div>}
</div>
</Layout>
);
};

export default SkeletonPulseActivitiy;
export default SkeletonWaveActivity;

SkeletonPulseActivitiy.displayName = "SkeletonPulseActivitiy";
SkeletonWaveActivity.displayName = "SkeletonWaveActivity";
21 changes: 0 additions & 21 deletions component-docs/components/LoadingTrigger.tsx

This file was deleted.

13 changes: 13 additions & 0 deletions component-docs/components/SkeletonControls.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { style } from "@vanilla-extract/css";

export const controlBlock = style({
display: "flex",
gap: "8px",
});

export const controlLabel = style({});

export const controlInput = style({
flex: 1,
border: "1px solid #e5e5e5",
});
51 changes: 51 additions & 0 deletions component-docs/components/SkeletonControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { BoxButton } from "@/seed-design/ui/box-button";
import {
useSkeletonActions,
useSkeletonDuration,
useSkeletonGradient,
useSkeletonLoading,
} from "@/stores/skeleton";
import * as React from "react";
import { controlBlock, controlInput, controlLabel } from "./SkeletonControls.css";

export const SkeletonControls = () => {
const isLoading = useSkeletonLoading();
const { toggleLoading, setControls } = useSkeletonActions();
const [duration, setDuration] = React.useState(useSkeletonDuration());
const [gradient, setGradient] = React.useState(useSkeletonGradient());

return (
<div>
<BoxButton variant={isLoading ? "neutral" : "brand"} onClick={toggleLoading}>
{isLoading ? "Stop Loading" : "Start Loading"}
</BoxButton>
<div>
<div className={controlBlock}>
<label className={controlLabel} htmlFor="duration">
Duration
</label>
<input
className={controlInput}
id="duration"
value={duration}
onChange={(e) => setDuration(e.target.value)}
/>
</div>
<div className={controlBlock}>
<label className={controlLabel} htmlFor="duration">
Gradient
</label>
<input
className={controlInput}
id="gradient"
value={gradient}
onChange={(e) => setGradient(e.target.value)}
/>
</div>
<BoxButton type="button" onClick={() => setControls({ duration, gradient })}>
적용
</BoxButton>
</div>
</div>
);
};
10 changes: 5 additions & 5 deletions component-docs/pages/patterns/skeleton.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Stackflow } from "@/components/Stackflow";
import { LoadingTrigger } from '@/components/LoadingTrigger';
import SkeletonPulseActivity from "@/activities/skeleton/SkeletonPulseActivitiy";
import { SkeletonControls } from '@/components/SkeletonControls';
import SkeletonWaveActivity from "@/activities/skeleton/SkeletonWaveActivity";

# Skeleton

### Pulse
### Wave

<Stackflow Activity={SkeletonPulseActivity} />
<Stackflow Activity={SkeletonWaveActivity} />

<LoadingTrigger />
<SkeletonControls />
11 changes: 6 additions & 5 deletions component-docs/seed-design/ui/skeleton.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { recipe } from "@vanilla-extract/recipes";

// #F7F8F9
// #F7F8F950
const pulse = keyframes({
const wave = keyframes({
"0%": {
backgroundPositionX: "100%",
},
Expand All @@ -22,13 +22,14 @@ export const skeleton = recipe({

variants: {
type: {
pulse: {
backgroundImage: "linear-gradient(90deg, #F7F8F9 0%, #F7F8F950 20%, #F7F8F9 40%)",
wave: {
backgroundImage:
"var(--skeleton-gradient, linear-gradient(90deg, #F7F8F9 0%, #F7F8F950 20%, #F7F8F9 40%))",
backgroundSize: "200% 100%",
animationFillMode: "forwards",

animationName: pulse,
animationDuration: "1.5s",
animationName: wave,
animationDuration: "var(--skeleton-animation-duration, 1.5s)",
animationTimingFunction: "ease-in-out",
animationIterationCount: "infinite",
},
Expand Down
4 changes: 2 additions & 2 deletions component-docs/seed-design/ui/skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ interface SkeletonProps {
width: number | string;
height: number | string;
borderRadius: "circle" | "rounded" | "square";
type?: "pulse";
type?: "wave";
}

// TODO: Spec
// TODO: Recipe
export const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>((props, ref) => {
const { width, height, borderRadius, type = "pulse" } = props;
const { width, height, borderRadius, type = "wave" } = props;
return (
<div
ref={ref}
Expand Down
8 changes: 8 additions & 0 deletions component-docs/stores/skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@ import { create } from "zustand";

interface SkeletonState {
isLoading: boolean;
duration: string;
gradient: string;
actions: {
toggleLoading: () => void;
setControls: (state: { duration: string; gradient: string }) => void;
};
}

const useSkeleton = create<SkeletonState>((set) => ({
isLoading: true,
duration: "1.5s",
gradient: "linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)",
actions: {
toggleLoading: () => set((state) => ({ isLoading: !state.isLoading })),
setControls: set,
},
}));

export const useSkeletonLoading = () => useSkeleton((state) => state.isLoading);
export const useSkeletonActions = () => useSkeleton((state) => state.actions);
export const useSkeletonDuration = () => useSkeleton((state) => state.duration);
export const useSkeletonGradient = () => useSkeleton((state) => state.gradient);

0 comments on commit cf8d15d

Please sign in to comment.