Shadcn conversion, more styling, sheet select step

This commit is contained in:
2025-02-19 01:59:51 -05:00
parent 5bf265ed46
commit 110f4ec332
4 changed files with 109 additions and 63 deletions

View File

@@ -1,8 +1,12 @@
import type React from "react" import type React from "react"
import type { Column, Columns } from "../MatchColumnsStep" import type { Column, Columns } from "../MatchColumnsStep"
import { ColumnType } from "../MatchColumnsStep"
import { useRsi } from "../../../hooks/useRsi" import { useRsi } from "../../../hooks/useRsi"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
import { Box } from "@/components/ui/box"
import { Text } from "@/components/ui/text"
import { FadingWrapper } from "@/components/ui/fading-wrapper"
type ColumnGridProps<T extends string> = { type ColumnGridProps<T extends string> = {
columns: Columns<T> columns: Columns<T>
@@ -22,9 +26,13 @@ export const ColumnGrid = <T extends string>({
isLoading, isLoading,
}: ColumnGridProps<T>) => { }: ColumnGridProps<T>) => {
const { translations } = useRsi() const { translations } = useRsi()
const columnWidth = 250 const normalColumnWidth = 250
const ignoredColumnWidth = 48 // 12 units = 3rem = 48px
const gap = 16 const gap = 16
const totalWidth = columns.length * columnWidth + (columns.length - 1) * gap const totalWidth = columns.reduce((acc, col) =>
acc + (col.type === ColumnType.ignored ? ignoredColumnWidth : normalColumnWidth) + gap,
-gap // Subtract one gap since we need gaps between columns only
)
return ( return (
<div className="flex h-[calc(100vh-9.5rem)] flex-col"> <div className="flex h-[calc(100vh-9.5rem)] flex-col">
@@ -44,18 +52,20 @@ export const ColumnGrid = <T extends string>({
</h3> </h3>
<div className="relative"> <div className="relative">
<div <div
className="grid gap-4" className="grid auto-cols-fr gap-4"
style={{ style={{
gridTemplateColumns: `repeat(${columns.length}, ${columnWidth}px)`, gridTemplateColumns: columns.map(col =>
`${col.type === ColumnType.ignored ? ignoredColumnWidth : normalColumnWidth}px`
).join(" "),
}} }}
> >
{columns.map((column, index) => ( {columns.map((column, index) => (
<div key={column.header + index} className="relative"> <div key={column.header + index}>
{userColumn(column)} {userColumn(column)}
</div> </div>
))} ))}
</div> </div>
<div className="pointer-events-none absolute bottom-0 left-0 right-0 h-24 bg-gradient-to-b from-transparent to-background" /> <div className="pointer-events-none absolute bottom-0 left-0 right-0 h-16 bg-gradient-to-b from-transparent via-background/50 to-background" />
</div> </div>
</div> </div>
@@ -65,9 +75,11 @@ export const ColumnGrid = <T extends string>({
{translations.matchColumnsStep.templateTitle} {translations.matchColumnsStep.templateTitle}
</h3> </h3>
<div <div
className="grid gap-4" className="grid auto-cols-fr gap-4"
style={{ style={{
gridTemplateColumns: `repeat(${columns.length}, ${columnWidth}px)`, gridTemplateColumns: columns.map(col =>
`${col.type === ColumnType.ignored ? ignoredColumnWidth : normalColumnWidth}px`
).join(" "),
}} }}
> >
{columns.map((column, index) => ( {columns.map((column, index) => (

View File

@@ -49,15 +49,7 @@ export const TemplateColumn = <T extends string>({ column, onChange, onSubChange
selectOptions.find(({ value }: { value: string }) => "value" in column && column.value === value)?.value selectOptions.find(({ value }: { value: string }) => "value" in column && column.value === value)?.value
if (isIgnored) { if (isIgnored) {
return ( return null
<Card className="h-full opacity-50">
<CardHeader className="p-4">
<p className="text-sm text-muted-foreground">
{translations.matchColumnsStep.ignoredColumnText}
</p>
</CardHeader>
</Card>
)
} }
return ( return (
@@ -86,8 +78,8 @@ export const TemplateColumn = <T extends string>({ column, onChange, onSubChange
</Select> </Select>
</div> </div>
{isChecked && ( {isChecked && (
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-primary/10"> <div className="flex h-8 w-8 items-center justify-center rounded-full border border-green-700 bg-green-300 dark:bg-green-900/20">
<Check className="h-4 w-4 text-primary" /> <Check className="h-4 w-4 text-green-700 dark:text-green-500" />
</div> </div>
)} )}
</CardHeader> </CardHeader>

View File

@@ -1,6 +1,6 @@
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader } from "@/components/ui/card" import { Card, CardContent, CardHeader } from "@/components/ui/card"
import { X, Undo2 } from "lucide-react" import { X, RotateCcw } from "lucide-react"
import type { Column } from "../MatchColumnsStep" import type { Column } from "../MatchColumnsStep"
import { ColumnType } from "../MatchColumnsStep" import { ColumnType } from "../MatchColumnsStep"
import type { RawData } from "../../../types" import type { RawData } from "../../../types"
@@ -22,35 +22,52 @@ export const UserTableColumn = <T extends string>(props: UserTableColumnProps<T>
} = props } = props
const isIgnored = type === ColumnType.ignored const isIgnored = type === ColumnType.ignored
if (isIgnored) {
return (
<Card className="h-full w-12 bg-muted/50">
<CardHeader className="flex flex-col items-center space-y-4 p-2">
<Button
variant="ghost"
size="icon"
onClick={() => onRevertIgnore(index)}
className="h-8 w-8"
>
<RotateCcw className="h-4 w-4" />
</Button>
<div
className="vertical-text font-medium text-muted-foreground"
style={{ writingMode: 'vertical-rl', textOrientation: 'mixed', transform: 'rotate(180deg)' }}
>
{header}
</div>
</CardHeader>
</Card>
)
}
return ( return (
<Card className={cn( <Card className="h-full">
"h-full transition-opacity",
isIgnored && "opacity-50"
)}>
<CardHeader className="flex flex-row items-center justify-between space-x-2 p-4"> <CardHeader className="flex flex-row items-center justify-between space-x-2 p-4">
<h4 className="truncate font-medium leading-none"> <p className="font-medium">
{header} {header}
</h4> </p>
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
onClick={() => isIgnored ? onRevertIgnore(index) : onIgnore(index)} onClick={() => onIgnore(index)}
className="h-8 w-8 shrink-0" className="h-8 w-8"
> >
{isIgnored ? <Undo2 className="h-4 w-4" /> : <X className="h-4 w-4" />} <X className="h-4 w-4" />
</Button> </Button>
</CardHeader> </CardHeader>
<CardContent className="space-y-2 p-4"> <CardContent className="space-y-2 p-4">
{entries.slice(0, 3).map((entry, i) => ( {entries.map((entry, i) => (
<div <p
key={`${entry || ""}-${i}`} key={`${entry || ""}-${i}`}
className={cn( className="truncate text-sm text-muted-foreground"
"truncate px-3 py-2 text-sm",
isIgnored ? "text-muted-foreground" : "text-foreground"
)}
> >
{entry || ""} {entry}
</div> </p>
))} ))}
</CardContent> </CardContent>
</Card> </Card>

View File

@@ -1,8 +1,9 @@
import { Heading, ModalBody, Radio, RadioGroup, Stack, useStyleConfig, Text } from "@chakra-ui/react"
import { useCallback, useState } from "react" import { useCallback, useState } from "react"
import { ContinueButton } from "../../components/ContinueButton"
import { useRsi } from "../../hooks/useRsi" import { useRsi } from "../../hooks/useRsi"
import type { themeOverrides } from "../../theme" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import { Label } from "@/components/ui/label"
import { Button } from "@/components/ui/button"
import { ChevronLeft } from "lucide-react"
type SelectSheetProps = { type SelectSheetProps = {
sheetNames: string[] sheetNames: string[]
@@ -14,9 +15,7 @@ export const SelectSheetStep = ({ sheetNames, onContinue, onBack }: SelectSheetP
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const { translations } = useRsi() const { translations } = useRsi()
const [value, setValue] = useState(sheetNames[0]) const [value, setValue] = useState(sheetNames[0])
const styles = useStyleConfig(
"SelectSheetStep",
) as (typeof themeOverrides)["components"]["SelectSheetStep"]["baseStyle"]
const handleOnContinue = useCallback( const handleOnContinue = useCallback(
async (data: typeof value) => { async (data: typeof value) => {
setIsLoading(true) setIsLoading(true)
@@ -27,26 +26,52 @@ export const SelectSheetStep = ({ sheetNames, onContinue, onBack }: SelectSheetP
) )
return ( return (
<> <div className="flex h-[calc(100vh-9.5rem)] flex-col">
<ModalBody alignItems="center" justifyContent="center" p={8} flex={1}> <div className="flex-1 overflow-hidden">
<Heading {...styles.heading}>{translations.uploadStep.selectSheet.title}</Heading> <div className="px-8 py-6">
<RadioGroup onChange={(value) => setValue(value)} value={value}> <div className="mb-8">
<Stack spacing={8}> <h2 className="text-3xl font-semibold text-foreground">
{translations.uploadStep.selectSheet.title}
</h2>
</div>
<RadioGroup
value={value}
onValueChange={setValue}
className="space-y-4"
>
{sheetNames.map((sheetName) => ( {sheetNames.map((sheetName) => (
<Radio value={sheetName} key={sheetName} {...styles.radio}> <div key={sheetName} className="flex items-center space-x-2">
<Text {...styles.radioLabel}>{sheetName}</Text> <RadioGroupItem value={sheetName} id={sheetName} />
</Radio> <Label
htmlFor={sheetName}
className="text-base"
>
{sheetName}
</Label>
</div>
))} ))}
</Stack> </RadioGroup>
</RadioGroup> </div>
</ModalBody> </div>
<ContinueButton <div className="flex items-center justify-between border-t p-6 bg-muted">
isLoading={isLoading} {onBack && (
onContinue={() => handleOnContinue(value)} <Button
onBack={onBack} variant="ghost"
title={translations.uploadStep.selectSheet.nextButtonTitle} onClick={onBack}
backTitle={translations.uploadStep.selectSheet.backButtonTitle} className="gap-2"
/> >
</> <ChevronLeft className="h-4 w-4" />
{translations.uploadStep.selectSheet.backButtonTitle}
</Button>
)}
<div className="flex-1" />
<Button
onClick={() => handleOnContinue(value)}
disabled={isLoading}
>
{translations.uploadStep.selectSheet.nextButtonTitle}
</Button>
</div>
</div>
) )
} }