-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/all panels styling #87
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
Changes from 6 commits
213f209
3f89b90
5c070f3
558c038
b13e304
91eb141
7f82bd2
3f3f4d3
e494cfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { type Image } from "@tissuumaps/core"; | ||
|
|
||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| import { Fieldset, FieldsetLegend } from "../../common/fieldset"; | ||
|
|
||
| export type ImagesLayersPanelProps = { | ||
| image: Image; | ||
| className?: string; | ||
| }; | ||
|
|
||
| export function ImagesLayersPanel({ className }: ImagesLayersPanelProps) { | ||
| return ( | ||
| <Fieldset | ||
| className={cn("flex flex-col gap-y-2 border rounded-md p-2", className)} | ||
| > | ||
| <FieldsetLegend className="font-medium text-foreground"> | ||
| Layers | ||
| </FieldsetLegend> | ||
| </Fieldset> | ||
| ); | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import { type Image } from "@tissuumaps/core"; | ||
|
|
||
| import { Input } from "@/components/ui/input"; | ||
| import { Switch } from "@/components/ui/switch"; | ||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| import { useTissUUmaps } from "../../../store"; | ||
| import { Field, FieldLabel } from "../../common/field"; | ||
| import { Fieldset, FieldsetLegend } from "../../common/fieldset"; | ||
|
|
||
| export type ImagesSettingsPanelProps = { | ||
| image: Image; | ||
| className?: string; | ||
| }; | ||
|
|
||
| export function ImagesSettingsPanel({ | ||
| image, | ||
| className, | ||
| }: ImagesSettingsPanelProps) { | ||
| const updateImage = useTissUUmaps((state) => state.updateImage); | ||
|
|
||
| return ( | ||
| <Fieldset | ||
| className={cn("flex flex-col gap-y-2 border rounded-md p-2", className)} | ||
| > | ||
| <FieldsetLegend className="font-medium text-foreground"> | ||
| Settings | ||
| </FieldsetLegend> | ||
| <Field> | ||
| <FieldLabel>Name</FieldLabel> | ||
| <Input | ||
| value={image.name} | ||
| onChange={(event) => | ||
| updateImage(image.id, { name: event.target.value }) | ||
| } | ||
| /> | ||
| </Field> | ||
| <Field> | ||
| <FieldLabel>Visibility</FieldLabel> | ||
| <div className="flex flex-row items-center gap-x-2"> | ||
| <Switch | ||
| checked={image.visibility} | ||
| onCheckedChange={(checked) => | ||
| updateImage(image.id, { visibility: checked }) | ||
| } | ||
| /> | ||
| {image.visibility ? "Visible" : "Hidden"} | ||
| </div> | ||
| </Field> | ||
| <Field> | ||
| <FieldLabel>Opacity</FieldLabel> | ||
| <Input | ||
| type="number" | ||
| min={0} | ||
| max={1} | ||
| step={0.01} | ||
| value={image.opacity} | ||
| onChange={(event) => { | ||
| const opacity = event.target.valueAsNumber; | ||
| if (Number.isFinite(opacity)) { | ||
| updateImage(image.id, { | ||
| opacity: Math.min(Math.max(0, opacity), 1), | ||
| }); | ||
| } | ||
| }} | ||
| /> | ||
| </Field> | ||
| </Fieldset> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,16 @@ | ||
| import { DragDropProvider } from "@dnd-kit/react"; | ||
| import { isSortable, useSortable } from "@dnd-kit/react/sortable"; | ||
| import { GripVertical } from "lucide-react"; | ||
| import { EyeIcon, EyeOffIcon, GripVertical, Trash2Icon } from "lucide-react"; | ||
|
|
||
| import { type Image } from "@tissuumaps/core"; | ||
|
|
||
| import { Button } from "@/components/ui/button"; | ||
| import { | ||
| InputGroup, | ||
| InputGroupAddon, | ||
| InputGroupInput, | ||
| } from "@/components/ui/input-group"; | ||
|
|
||
| import { useTissUUmaps } from "../../../store"; | ||
| import { | ||
| Accordion, | ||
|
|
@@ -13,7 +20,9 @@ import { | |
| AccordionTrigger, | ||
| AccordionTriggerUpDownIcon, | ||
| } from "../../common/accordion"; | ||
| import { ImagesPanelItem } from "./ImagesPanelItem"; | ||
| import { ImagesLayersPanel } from "./ImagesLayersPanel"; | ||
| import { ImagesSettingsPanel } from "./ImagesSettingsPanel"; | ||
| import { ImagesSourcePanel } from "./ImagesSourcePanel"; | ||
|
|
||
| export type ImagesPanelProps = { | ||
| className?: string; | ||
|
|
@@ -28,8 +37,6 @@ export function ImagesPanel({ className }: ImagesPanelProps) { | |
| onDragEnd={(event) => { | ||
| const { source, canceled } = event.operation; | ||
| if (isSortable(source) && !canceled) { | ||
| // dnd-kit optimistically updates the DOM | ||
| // https://github.com/clauderic/dnd-kit/issues/1564 | ||
| moveImage(source.id as string, source.index); | ||
| } | ||
| }} | ||
|
|
@@ -49,18 +56,70 @@ type ImageAccordionItemProps = { | |
| }; | ||
|
|
||
| function ImageAccordionItem({ image, index }: ImageAccordionItemProps) { | ||
| const updateImage = useTissUUmaps((state) => state.updateImage); | ||
| const deleteImage = useTissUUmaps((state) => state.deleteImage); | ||
|
|
||
| const { ref, handleRef } = useSortable({ id: image.id, index }); | ||
|
|
||
| return ( | ||
| <AccordionItem render={<div ref={ref} />}> | ||
| <AccordionHeader> | ||
| <GripVertical ref={handleRef} /> | ||
| <AccordionTrigger>{image.name}</AccordionTrigger> | ||
| <AccordionTriggerUpDownIcon className="ml-auto" /> | ||
| </AccordionHeader> | ||
| <AccordionPanel> | ||
| <ImagesPanelItem image={image} /> | ||
| </AccordionPanel> | ||
| </AccordionItem> | ||
| <div ref={ref}> | ||
| <AccordionItem className="border rounded-md bg-sidebar p-2"> | ||
| <AccordionHeader> | ||
| <GripVertical ref={handleRef} /> | ||
| <div className="flex-1 w-full"> | ||
| <AccordionTrigger className="w-full cursor-pointer"> | ||
| {image.name} | ||
| </AccordionTrigger> | ||
| </div> | ||
| <div className="ml-auto flex flex-row items-center gap-x-2"> | ||
| <InputGroup className="w-24"> | ||
| <InputGroupAddon>OPA</InputGroupAddon> | ||
| <InputGroupInput | ||
| type="number" | ||
| min={0} | ||
| max={1} | ||
| step={0.01} | ||
| value={image.opacity} | ||
| onChange={(event) => { | ||
| const opacity = event.target.valueAsNumber; | ||
| if (Number.isFinite(opacity)) { | ||
| updateImage(image.id, { | ||
| opacity: Math.min(Math.max(0, opacity), 1), | ||
| }); | ||
| } | ||
| }} | ||
| /> | ||
| </InputGroup> | ||
| <Button | ||
| variant="ghost" | ||
| onClick={() => | ||
| updateImage(image.id, { visibility: !image.visibility }) | ||
| } | ||
| > | ||
| {image.visibility ? <EyeIcon /> : <EyeOffIcon />} | ||
| </Button> | ||
|
Comment on lines
+95
to
+102
|
||
| <Button | ||
| variant="ghost" | ||
| onClick={() => { | ||
| if ( | ||
cavenel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| window.confirm("Are you sure you want to delete this image?") | ||
| ) { | ||
| deleteImage(image.id); | ||
| } | ||
| }} | ||
| title="Delete image" | ||
| > | ||
| <Trash2Icon /> | ||
| </Button> | ||
| </div> | ||
| <AccordionTriggerUpDownIcon /> | ||
| </AccordionHeader> | ||
| <AccordionPanel className="pt-2 flex flex-col gap-y-2"> | ||
| <ImagesSourcePanel image={image} className="bg-card" /> | ||
| <ImagesSettingsPanel image={image} className="bg-card" /> | ||
| <ImagesLayersPanel image={image} className="bg-card" /> | ||
| </AccordionPanel> | ||
| </AccordionItem> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { type Labels } from "@tissuumaps/core"; | ||
|
|
||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| import { Fieldset, FieldsetLegend } from "../../common/fieldset"; | ||
|
|
||
| export type LabelsLayersPanelProps = { | ||
| labels: Labels; | ||
| className?: string; | ||
| }; | ||
|
|
||
| export function LabelsLayersPanel({ className }: LabelsLayersPanelProps) { | ||
| return ( | ||
| <Fieldset | ||
| className={cn("flex flex-col gap-y-2 border rounded-md p-2", className)} | ||
| > | ||
| <FieldsetLegend className="font-medium text-foreground"> | ||
| Layers | ||
| </FieldsetLegend> | ||
| </Fieldset> | ||
| ); | ||
| } |
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.