diff --git a/frontend/app/element/multiselect.scss b/frontend/app/element/multiselect.scss new file mode 100644 index 000000000..850de4229 --- /dev/null +++ b/frontend/app/element/multiselect.scss @@ -0,0 +1,44 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +.multi-select { + border-radius: 7px; + background: rgb(from var(--block-bg-color) r g b / 70%); + color: var(--main-text-color); + padding: 4px; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 3px; + align-self: stretch; + border: 1px solid rgb(from var(--main-text-color) r g b / 15%); + width: 100%; + + .option { + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + padding: 9px 12px; + border-radius: 4px; + align-self: stretch; + border: 1px solid transparent; + + &:hover { + background-color: rgb(from var(--main-bg-color) r g b / 60%); + } + + &.selected { + border: 1px solid var(--success-color); + background: rgb(from var(--success-color) r g b / 15%); + + i { + color: var(--success-color); + } + } + } + + i { + font-size: 1rem; + } +} diff --git a/frontend/app/element/multiselect.stories.tsx b/frontend/app/element/multiselect.stories.tsx new file mode 100644 index 000000000..8c6c4de1f --- /dev/null +++ b/frontend/app/element/multiselect.stories.tsx @@ -0,0 +1,55 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import type { Meta, StoryObj } from "@storybook/react"; +import { MultiSelect } from "./multiselect"; + +const meta: Meta = { + title: "Components/MultiSelect", + component: MultiSelect, + args: { + options: [ + { label: "macOS", value: "macos" }, + { label: "Windows", value: "windows" }, + { label: "Linux", value: "linux" }, + ], + }, + argTypes: { + options: { + description: "List of selectable options.", + }, + selectedValues: { + description: "Array of selected option values.", + }, + onChange: { + description: "Callback triggered when selected options change.", + action: "changed", + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const WithPreselectedValues: Story = { + render: (args) => ( +
+ +
+ ), + args: { + selectedValues: ["macos", "windows"], + }, +}; + +export const WithNoSelection: Story = { + render: (args) => ( +
+ +
+ ), + args: { + selectedValues: [], + }, +}; diff --git a/frontend/app/element/multiselect.tsx b/frontend/app/element/multiselect.tsx new file mode 100644 index 000000000..45cfe712e --- /dev/null +++ b/frontend/app/element/multiselect.tsx @@ -0,0 +1,46 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import React, { useState } from "react"; +import "./MultiSelect.scss"; + +type Option = { + label: string; + value: string; +}; + +type MultiSelectProps = { + options: Option[]; + selectedValues?: string[]; // Pre-selected options + onChange: (values: string[]) => void; +}; + +const MultiSelect: React.FC = ({ options, selectedValues = [], onChange }) => { + const [selected, setSelected] = useState(selectedValues); + + const handleToggle = (value: string) => { + const newSelected = selected.includes(value) + ? selected.filter((v) => v !== value) // Remove if already selected + : [...selected, value]; // Add if not selected + + setSelected(newSelected); + onChange(newSelected); + }; + + return ( +
+ {options.map((option) => ( +
handleToggle(option.value)} + > + {option.label} + {selected.includes(option.value) && } +
+ ))} +
+ ); +}; + +export { MultiSelect }; diff --git a/frontend/app/element/notification.scss b/frontend/app/element/notification.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/app/element/notification.tsx b/frontend/app/element/notification.tsx deleted file mode 100644 index e69de29bb..000000000