From e7da462277be1abd3ef03bc60d940c2c4f3fed45 Mon Sep 17 00:00:00 2001 From: Afonso Martins Date: Sat, 5 Jul 2025 01:08:09 +0100 Subject: [PATCH 1/6] feat: switch component done --- src/app/components/switch_component.tsx | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/app/components/switch_component.tsx diff --git a/src/app/components/switch_component.tsx b/src/app/components/switch_component.tsx new file mode 100644 index 0000000..143c2d3 --- /dev/null +++ b/src/app/components/switch_component.tsx @@ -0,0 +1,36 @@ +"use client"; + +import React, { useState } from 'react'; + +const ToggleSwitch = ({ initialState = false, onToggle }: { initialState?: boolean, onToggle?: (state: boolean) => void }) => { + const [isOn, setIsOn] = useState(initialState); + + const handleToggle = () => { + const newState = !isOn; + setIsOn(newState); + if (onToggle) { + onToggle(newState); + } + }; + + return ( + + ); +}; +export default ToggleSwitch; From b2f40a35bc574823cf2be79dc5b8dd3b09a2e1a0 Mon Sep 17 00:00:00 2001 From: Afonso Martins Date: Tue, 8 Jul 2025 23:38:34 +0100 Subject: [PATCH 2/6] feat: review --- src/app/components/switch_component.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/app/components/switch_component.tsx b/src/app/components/switch_component.tsx index 143c2d3..241d5d9 100644 --- a/src/app/components/switch_component.tsx +++ b/src/app/components/switch_component.tsx @@ -1,8 +1,13 @@ "use client"; -import React, { useState } from 'react'; +import { useState } from 'react'; -const ToggleSwitch = ({ initialState = false, onToggle }: { initialState?: boolean, onToggle?: (state: boolean) => void }) => { +interface IToggleSwitchProps { + initialState?: boolean; + onToggle?: (state: boolean) => void; +} + +const ToggleSwitch: React.FC = ({ initialState = false, onToggle }) => { const [isOn, setIsOn] = useState(initialState); const handleToggle = () => { @@ -17,7 +22,7 @@ const ToggleSwitch = ({ initialState = false, onToggle }: { initialState?: boole ); }; -export default ToggleSwitch; \ No newline at end of file +export default ToggleSwitch; From 5d5e6d28f675d3b231cf3343f10ed4a7d92f0f8f Mon Sep 17 00:00:00 2001 From: Afonso Martins Date: Thu, 10 Jul 2025 22:17:31 +0100 Subject: [PATCH 4/6] feat: component in the storybook --- src/app/components/switch_component.tsx | 30 ++++++- src/stories/components/Switch/Switch.tsx | 48 ++++++++++ .../components/Switch/ToggleSwitch.stories.ts | 59 +++++++++++++ .../components/Switch/switch_component.css | 87 +++++++++++++++++++ 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 src/stories/components/Switch/Switch.tsx create mode 100644 src/stories/components/Switch/ToggleSwitch.stories.ts create mode 100644 src/stories/components/Switch/switch_component.css diff --git a/src/app/components/switch_component.tsx b/src/app/components/switch_component.tsx index af72337..9a8f418 100644 --- a/src/app/components/switch_component.tsx +++ b/src/app/components/switch_component.tsx @@ -4,11 +4,13 @@ import { useState } from "react"; interface IToggleSwitchProps { initialState?: boolean; + size?: "small" | "medium" | "large"; onToggle?: (state: boolean) => void; } const ToggleSwitch: React.FC = ({ initialState = false, + size = "medium", onToggle, }) => { const [isOn, setIsOn] = useState(initialState); @@ -21,16 +23,40 @@ const ToggleSwitch: React.FC = ({ } }; + const getSizeClasses = () => { + switch (size) { + case "small": + return "h-5 w-9"; + case "large": + return "h-8 w-14"; + default: + return "h-6 w-11"; + } + }; + + const getHandleClasses = () => { + switch (size) { + case "small": + return `h-3 w-3 ${isOn ? "translate-x-5" : "translate-x-1"}`; + case "large": + return `h-6 w-6 ${isOn ? "translate-x-6" : "translate-x-1"}`; + default: + return `h-4 w-4 ${isOn ? "translate-x-6" : "translate-x-1"}`; + } + }; + return ( ); diff --git a/src/stories/components/Switch/Switch.tsx b/src/stories/components/Switch/Switch.tsx new file mode 100644 index 0000000..d9084ff --- /dev/null +++ b/src/stories/components/Switch/Switch.tsx @@ -0,0 +1,48 @@ +import './switch_component.css'; +import { useState, useEffect } from 'react'; + +export interface IToggleSwitchProps { + /** Initial state of the switch */ + initialState?: boolean; + /** How large should the switch be? */ + size?: 'small' | 'medium' | 'large'; + /** Optional toggle handler */ + onToggle?: (state: boolean) => void; +} + +/** Primary UI component for user interaction */ +export const Switch = ({ + initialState = false, + size = 'medium', + onToggle, + ...props +}: IToggleSwitchProps) => { + const [isOn, setIsOn] = useState(initialState); + + // Atualiza o estado quando initialState muda (importante para o Storybook) + useEffect(() => { + setIsOn(initialState); + }, [initialState]); + + const handleToggle = () => { + const newState = !isOn; + setIsOn(newState); + if (onToggle) { + onToggle(newState); + } + }; + + return ( + + ); +}; \ No newline at end of file diff --git a/src/stories/components/Switch/ToggleSwitch.stories.ts b/src/stories/components/Switch/ToggleSwitch.stories.ts new file mode 100644 index 0000000..087659b --- /dev/null +++ b/src/stories/components/Switch/ToggleSwitch.stories.ts @@ -0,0 +1,59 @@ +import type { Meta, StoryObj } from '@storybook/nextjs-vite'; + +import { fn } from 'storybook/test'; + +import { Switch } from './Switch'; + +// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export +const meta = { + title: 'Example/Switch', + component: Switch, + parameters: { + // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout + layout: 'centered', + }, + // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs + tags: ['autodocs'], + // More on argTypes: https://storybook.js.org/docs/api/argtypes + argTypes: { + initialState: { control: 'boolean' }, + size: { + control: { type: 'select' }, + options: ['small', 'medium', 'large'], + }, + }, + // Use `fn` to spy on the onToggle arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args + args: { onToggle: fn() }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args +export const Primary: Story = { + args: { + initialState: false, + size: 'medium', + }, +}; + +export const Secondary: Story = { + args: { + initialState: true, + size: 'medium', + }, +}; + +export const Large: Story = { + args: { + initialState: false, + size: 'large', + }, +}; + +export const Small: Story = { + args: { + initialState: true, + size: 'small', + }, +}; \ No newline at end of file diff --git a/src/stories/components/Switch/switch_component.css b/src/stories/components/Switch/switch_component.css new file mode 100644 index 0000000..a655874 --- /dev/null +++ b/src/stories/components/Switch/switch_component.css @@ -0,0 +1,87 @@ +.storybook-switch { + position: relative; + display: inline-flex; + align-items: center; + cursor: pointer; + border: 0; + border-radius: 9999px; + transition: background-color 0.2s ease-in-out; + outline: none; +} + +.storybook-switch:focus { + box-shadow: 0 0 0 1px rgba(251, 146, 60, 0.3); +} + +.storybook-switch--off { + background-color: #d1d5db; +} + +.storybook-switch--on { + background-color: #f97316; +} + +.storybook-switch__handle { + display: inline-block; + background-color: white; + border-radius: 50%; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + transition: transform 0.2s ease-in-out; +} + +.storybook-switch--small { + height: 20px; + width: 36px; +} + +.storybook-switch--small .storybook-switch__handle { + height: 12px; + width: 12px; + transform: translateX(4px); +} + +.storybook-switch--small.storybook-switch--on .storybook-switch__handle { + transform: translateX(20px); +} + +.storybook-switch--medium { + height: 24px; + width: 44px; +} + +.storybook-switch--medium .storybook-switch__handle { + height: 16px; + width: 16px; + transform: translateX(4px); +} + +.storybook-switch--medium.storybook-switch--on .storybook-switch__handle { + transform: translateX(24px); +} + +.storybook-switch--large { + height: 32px; + width: 56px; +} + +.storybook-switch--large .storybook-switch__handle { + height: 24px; + width: 24px; + transform: translateX(4px); +} + +.storybook-switch--large.storybook-switch--on .storybook-switch__handle { + transform: translateX(28px); +} + +.storybook-switch__sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} \ No newline at end of file From 31cfda4f10051627b6b6c68f167778469106beda Mon Sep 17 00:00:00 2001 From: Afonso Martins Date: Thu, 10 Jul 2025 22:39:41 +0100 Subject: [PATCH 5/6] feat: component in the storybook --- .storybook/preview.ts | 2 + .../Switch => }/ToggleSwitch.stories.ts | 12 +-- src/stories/components/Switch/Switch.tsx | 48 ---------- .../components/Switch/switch_component.css | 87 ------------------- 4 files changed, 8 insertions(+), 141 deletions(-) rename src/stories/{components/Switch => }/ToggleSwitch.stories.ts (86%) delete mode 100644 src/stories/components/Switch/Switch.tsx delete mode 100644 src/stories/components/Switch/switch_component.css diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 7889553..3a72168 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,5 +1,7 @@ import type { Preview } from '@storybook/nextjs-vite' +import "../src/app/globals.css"; + const preview: Preview = { parameters: { controls: { diff --git a/src/stories/components/Switch/ToggleSwitch.stories.ts b/src/stories/ToggleSwitch.stories.ts similarity index 86% rename from src/stories/components/Switch/ToggleSwitch.stories.ts rename to src/stories/ToggleSwitch.stories.ts index 087659b..c8e0777 100644 --- a/src/stories/components/Switch/ToggleSwitch.stories.ts +++ b/src/stories/ToggleSwitch.stories.ts @@ -2,12 +2,12 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite'; import { fn } from 'storybook/test'; -import { Switch } from './Switch'; +import ToggleSwitch from '../app/components/switch_component'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { - title: 'Example/Switch', - component: Switch, + title: 'Example/ToggleSwitch', + component: ToggleSwitch, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout layout: 'centered', @@ -24,20 +24,20 @@ const meta = { }, // Use `fn` to spy on the onToggle arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args args: { onToggle: fn() }, -} satisfies Meta; +} satisfies Meta; export default meta; type Story = StoryObj; // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args -export const Primary: Story = { +export const Enabled: Story = { args: { initialState: false, size: 'medium', }, }; -export const Secondary: Story = { +export const Disabled: Story = { args: { initialState: true, size: 'medium', diff --git a/src/stories/components/Switch/Switch.tsx b/src/stories/components/Switch/Switch.tsx deleted file mode 100644 index d9084ff..0000000 --- a/src/stories/components/Switch/Switch.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import './switch_component.css'; -import { useState, useEffect } from 'react'; - -export interface IToggleSwitchProps { - /** Initial state of the switch */ - initialState?: boolean; - /** How large should the switch be? */ - size?: 'small' | 'medium' | 'large'; - /** Optional toggle handler */ - onToggle?: (state: boolean) => void; -} - -/** Primary UI component for user interaction */ -export const Switch = ({ - initialState = false, - size = 'medium', - onToggle, - ...props -}: IToggleSwitchProps) => { - const [isOn, setIsOn] = useState(initialState); - - // Atualiza o estado quando initialState muda (importante para o Storybook) - useEffect(() => { - setIsOn(initialState); - }, [initialState]); - - const handleToggle = () => { - const newState = !isOn; - setIsOn(newState); - if (onToggle) { - onToggle(newState); - } - }; - - return ( - - ); -}; \ No newline at end of file diff --git a/src/stories/components/Switch/switch_component.css b/src/stories/components/Switch/switch_component.css deleted file mode 100644 index a655874..0000000 --- a/src/stories/components/Switch/switch_component.css +++ /dev/null @@ -1,87 +0,0 @@ -.storybook-switch { - position: relative; - display: inline-flex; - align-items: center; - cursor: pointer; - border: 0; - border-radius: 9999px; - transition: background-color 0.2s ease-in-out; - outline: none; -} - -.storybook-switch:focus { - box-shadow: 0 0 0 1px rgba(251, 146, 60, 0.3); -} - -.storybook-switch--off { - background-color: #d1d5db; -} - -.storybook-switch--on { - background-color: #f97316; -} - -.storybook-switch__handle { - display: inline-block; - background-color: white; - border-radius: 50%; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - transition: transform 0.2s ease-in-out; -} - -.storybook-switch--small { - height: 20px; - width: 36px; -} - -.storybook-switch--small .storybook-switch__handle { - height: 12px; - width: 12px; - transform: translateX(4px); -} - -.storybook-switch--small.storybook-switch--on .storybook-switch__handle { - transform: translateX(20px); -} - -.storybook-switch--medium { - height: 24px; - width: 44px; -} - -.storybook-switch--medium .storybook-switch__handle { - height: 16px; - width: 16px; - transform: translateX(4px); -} - -.storybook-switch--medium.storybook-switch--on .storybook-switch__handle { - transform: translateX(24px); -} - -.storybook-switch--large { - height: 32px; - width: 56px; -} - -.storybook-switch--large .storybook-switch__handle { - height: 24px; - width: 24px; - transform: translateX(4px); -} - -.storybook-switch--large.storybook-switch--on .storybook-switch__handle { - transform: translateX(28px); -} - -.storybook-switch__sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} \ No newline at end of file From ca8f57c805ff4cfb5149924f807a230d054a68bb Mon Sep 17 00:00:00 2001 From: Afonso Martins Date: Fri, 11 Jul 2025 22:30:53 +0100 Subject: [PATCH 6/6] feat: remove comments --- src/stories/ToggleSwitch.stories.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/stories/ToggleSwitch.stories.ts b/src/stories/ToggleSwitch.stories.ts index c8e0777..ac84c45 100644 --- a/src/stories/ToggleSwitch.stories.ts +++ b/src/stories/ToggleSwitch.stories.ts @@ -4,17 +4,13 @@ import { fn } from 'storybook/test'; import ToggleSwitch from '../app/components/switch_component'; -// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { title: 'Example/ToggleSwitch', component: ToggleSwitch, parameters: { - // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout layout: 'centered', }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs tags: ['autodocs'], - // More on argTypes: https://storybook.js.org/docs/api/argtypes argTypes: { initialState: { control: 'boolean' }, size: { @@ -22,14 +18,12 @@ const meta = { options: ['small', 'medium', 'large'], }, }, - // Use `fn` to spy on the onToggle arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args args: { onToggle: fn() }, } satisfies Meta; export default meta; type Story = StoryObj; -// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const Enabled: Story = { args: { initialState: false,