Skip to content
Closed
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
29 changes: 29 additions & 0 deletions apps/storybook/src/components/components/modal/Modal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { computed } from "vue";
import { modal } from "virtual:styleframe";

const props = withDefaults(
defineProps<{
color?: "light" | "dark" | "neutral";
variant?: "solid" | "soft" | "subtle";
size?: "sm" | "md" | "lg";
fullscreen?: boolean;
}>(),
{},
);

const classes = computed(() =>
modal({
color: props.color,
variant: props.variant,
size: props.size,
fullscreen: props.fullscreen ? "true" : "false",
}),
);
</script>

<template>
<div :class="classes">
<slot />
</div>
</template>
27 changes: 27 additions & 0 deletions apps/storybook/src/components/components/modal/ModalBody.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script setup lang="ts">
import { computed } from "vue";
import { modalBody } from "virtual:styleframe";

const props = withDefaults(
defineProps<{
color?: "light" | "dark" | "neutral";
variant?: "solid" | "soft" | "subtle";
size?: "sm" | "md" | "lg";
}>(),
{},
);

const classes = computed(() =>
modalBody({
color: props.color,
variant: props.variant,
size: props.size,
}),
);
</script>

<template>
<div :class="classes">
<slot />
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<p class="modal-description _margin:0"><slot /></p>
</template>
27 changes: 27 additions & 0 deletions apps/storybook/src/components/components/modal/ModalFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script setup lang="ts">
import { computed } from "vue";
import { modalFooter } from "virtual:styleframe";

const props = withDefaults(
defineProps<{
color?: "light" | "dark" | "neutral";
variant?: "solid" | "soft" | "subtle";
size?: "sm" | "md" | "lg";
}>(),
{},
);

const classes = computed(() =>
modalFooter({
color: props.color,
variant: props.variant,
size: props.size,
}),
);
</script>

<template>
<div :class="classes">
<slot />
</div>
</template>
27 changes: 27 additions & 0 deletions apps/storybook/src/components/components/modal/ModalHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script setup lang="ts">
import { computed } from "vue";
import { modalHeader } from "virtual:styleframe";

const props = withDefaults(
defineProps<{
color?: "light" | "dark" | "neutral";
variant?: "solid" | "soft" | "subtle";
size?: "sm" | "md" | "lg";
}>(),
{},
);

const classes = computed(() =>
modalHeader({
color: props.color,
variant: props.variant,
size: props.size,
}),
);
</script>

<template>
<div :class="classes">
<slot />
</div>
</template>
12 changes: 12 additions & 0 deletions apps/storybook/src/components/components/modal/ModalOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script setup lang="ts">
import { computed } from "vue";
import { modalOverlay } from "virtual:styleframe";

const classes = computed(() => modalOverlay({}));
</script>

<template>
<div :class="classes">
<slot />
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<strong class="modal-title"><slot /></strong>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
import Modal from "../Modal.vue";
import ModalHeader from "../ModalHeader.vue";
import ModalBody from "../ModalBody.vue";
import ModalFooter from "../ModalFooter.vue";
import ModalTitle from "../ModalTitle.vue";
import ModalDescription from "../ModalDescription.vue";

const colors = ["neutral", "light", "dark"] as const;
const variants = ["solid", "soft", "subtle"] as const;
</script>

<template>
<div class="modal-section">
<div v-for="variant in variants" :key="variant">
<div class="modal-label">{{ variant }}</div>
<div class="modal-row">
<Modal
v-for="color in colors"
:key="`${variant}-${color}`"
:color="color"
:variant="variant"
style="max-width: 300px"
>
<ModalHeader :color="color" :variant="variant">
<ModalTitle>{{ variant.charAt(0).toUpperCase() + variant.slice(1) }} {{ color.charAt(0).toUpperCase() + color.slice(1) }}</ModalTitle>
</ModalHeader>
<ModalBody>
<ModalDescription>This is a {{ variant }} {{ color }} modal.</ModalDescription>
</ModalBody>
<ModalFooter :color="color" :variant="variant">
Footer content
</ModalFooter>
</Modal>
</div>
</div>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import Modal from "../Modal.vue";
import ModalHeader from "../ModalHeader.vue";
import ModalBody from "../ModalBody.vue";
import ModalFooter from "../ModalFooter.vue";
import ModalTitle from "../ModalTitle.vue";
import ModalDescription from "../ModalDescription.vue";

const colors = ["neutral", "light", "dark"] as const;
const sizes = ["sm", "md", "lg"] as const;
const sizeTitles: Record<string, string> = {
sm: "Small",
md: "Medium",
lg: "Large",
};
</script>

<template>
<div class="modal-section">
<div v-for="size in sizes" :key="size">
<div class="modal-label">{{ size }}</div>
<div class="modal-row">
<Modal
v-for="color in colors"
:key="`${size}-${color}`"
:color="color"
:size="size"
>
<ModalHeader :color="color" :size="size">
<ModalTitle>{{ sizeTitles[size] }} {{ color.charAt(0).toUpperCase() + color.slice(1) }}</ModalTitle>
</ModalHeader>
<ModalBody :size="size">
<ModalDescription>This is a {{ size }} {{ color }} modal.</ModalDescription>
</ModalBody>
<ModalFooter :color="color" :size="size">
Footer content
</ModalFooter>
</Modal>
</div>
</div>
</div>
</template>
159 changes: 159 additions & 0 deletions apps/storybook/stories/components/modal.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import type { Meta, StoryObj } from "@storybook/vue3-vite";

import Modal from "@/components/components/modal/Modal.vue";
import ModalHeader from "@/components/components/modal/ModalHeader.vue";
import ModalBody from "@/components/components/modal/ModalBody.vue";
import ModalFooter from "@/components/components/modal/ModalFooter.vue";
import ModalTitle from "@/components/components/modal/ModalTitle.vue";
import ModalDescription from "@/components/components/modal/ModalDescription.vue";
import ModalGrid from "@/components/components/modal/preview/ModalGrid.vue";
import ModalSizeGrid from "@/components/components/modal/preview/ModalSizeGrid.vue";

const colors = ["neutral", "light", "dark"] as const;
const variants = ["solid", "soft", "subtle"] as const;
const sizes = ["sm", "md", "lg"] as const;

const meta = {
title: "Theme/Recipes/Modal",
component: Modal,
tags: ["autodocs"],
parameters: {
layout: "padded",
},
argTypes: {
color: {
control: "select",
options: colors,
description: "The color variant of the modal",
},
variant: {
control: "select",
options: variants,
description: "The visual style variant",
},
size: {
control: "select",
options: sizes,
description: "The size of the modal",
},
fullscreen: {
control: "boolean",
description: "Whether the modal is fullscreen",
},
},
render: (args) => ({
components: {
Modal,
ModalHeader,
ModalBody,
ModalFooter,
ModalTitle,
ModalDescription,
},
setup() {
return { args };
},
template: `
<Modal v-bind="args">
<ModalHeader v-bind="args">
<ModalTitle>Modal Title</ModalTitle>
</ModalHeader>
<ModalBody v-bind="args">
<ModalDescription>This is a modal description with some content.</ModalDescription>
</ModalBody>
<ModalFooter v-bind="args">
Footer content
</ModalFooter>
</Modal>
`,
}),
} satisfies Meta<typeof Modal>;

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

export const Default: Story = {
args: {
color: "neutral",
variant: "solid",
size: "md",
},
};

export const AllVariants: StoryObj = {
render: () => ({
components: { ModalGrid },
template: "<ModalGrid />",
}),
};

export const AllSizes: StoryObj = {
render: () => ({
components: { ModalSizeGrid },
template: "<ModalSizeGrid />",
}),
};

// Individual color stories
export const Neutral: Story = {
args: {
color: "neutral",
},
};

export const Light: Story = {
args: {
color: "light",
},
};

export const Dark: Story = {
args: {
color: "dark",
},
};

// Variant stories
export const Solid: Story = {
args: {
variant: "solid",
},
};

export const Soft: Story = {
args: {
variant: "soft",
},
};

export const Subtle: Story = {
args: {
variant: "subtle",
},
};

// Size stories
export const Small: Story = {
args: {
size: "sm",
},
};

export const Medium: Story = {
args: {
size: "md",
},
};

export const Large: Story = {
args: {
size: "lg",
},
};

// Fullscreen story
export const Fullscreen: Story = {
args: {
fullscreen: true,
},
};
Loading
Loading