Skip to content

Commit

Permalink
fix: fix paragraph item stacked height overflow issue (coaidev#99)
Browse files Browse the repository at this point in the history
  • Loading branch information
zmh-program committed Mar 11, 2024
1 parent 6f5dae5 commit 82d0f3c
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 54 deletions.
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@headlessui/react": "^1.7.18",
"@headlessui/tailwindcss": "^0.2.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-context-menu": "^2.1.4",
Expand Down
60 changes: 60 additions & 0 deletions app/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions app/src/assets/ui.less
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ input[type="number"] {
display: flex;
flex-direction: column;
margin: 0.5rem 0;
padding: 1.5rem;
padding: 1rem 1.5rem 0.25rem;
border-radius: var(--radius);
background: hsl(var(--background));
color: hsl(var(--text));
Expand Down Expand Up @@ -191,7 +191,6 @@ input[type="number"] {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
margin-bottom: 1.5rem;
align-items: center;
transform: translateY(-0.25rem);
}
Expand All @@ -205,6 +204,7 @@ input[type="number"] {
line-height: 1.1rem;
color: hsl(var(--text-secondary));
transition: .25s;
text-decoration: none !important;

&:before {
content: '';
Expand Down Expand Up @@ -273,6 +273,10 @@ input[type="number"] {
height: 0.25rem;
}

.paragraph-content {
transition: 1.5s ease-in-out;
}

.paragraph-footer {
display: flex;
flex-direction: row;
Expand Down
68 changes: 23 additions & 45 deletions app/src/components/Paragraph.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React from "react";
import { ChevronDown, Info } from "lucide-react";
import { Info } from "lucide-react";
import { cn } from "@/components/ui/lib/utils.ts";
import { Button } from "@/components/ui/button.tsx";
import Markdown from "@/components/Markdown.tsx";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion.tsx";

export type ParagraphProps = {
title?: string;
children: React.ReactNode;
className?: string;
configParagraph?: boolean;
isCollapsed?: boolean;
onCollapse?: () => void;
defaultCollapsed?: boolean;
};

function Paragraph({
Expand All @@ -20,51 +23,25 @@ function Paragraph({
className,
configParagraph,
isCollapsed,
onCollapse,
defaultCollapsed,
}: ParagraphProps) {
const [collapsed, setCollapsed] = React.useState(defaultCollapsed ?? false);

React.useEffect(() => onCollapse && onCollapse(), [collapsed]);

return (
<div
className={cn(
`paragraph`,
configParagraph && `config-paragraph`,
isCollapsed && `collapsable`,
collapsed && `collapsed`,
className,
)}
>
<div
className={`paragraph-header`}
onClick={() => setCollapsed(!collapsed)}
>
{title && <div className={`paragraph-title`}>{title}</div>}
<div className={`grow`} />
{isCollapsed && (
<Button size={`icon`} variant={`ghost`} className={`w-8 h-8`}>
<ChevronDown
className={cn(
`w-4 h-4 transition-transform duration-300`,
collapsed && `transform rotate-180`,
)}
/>
</Button>
<Accordion type={`single`} collapsible={isCollapsed} defaultValue={"item"}>
<AccordionItem
value={`item`}
className={cn(
`paragraph`,
configParagraph && `config-paragraph`,
className,
)}
</div>
<div
className={`paragraph-content`}
style={
{
"--max-height": collapsed ? "0px" : "1000px",
} as React.CSSProperties
}
>
{children}
</div>
</div>
<AccordionTrigger className={`paragraph-header`}>
<div className={`paragraph-title`}>{title ?? ""}</div>
</AccordionTrigger>
<AccordionContent className={`paragraph-content mt-2`}>
{children}
</AccordionContent>
</AccordionItem>
</Accordion>
);
}

Expand All @@ -88,6 +65,7 @@ type ParagraphDescriptionProps = {
children: string;
border?: boolean;
};

export function ParagraphDescription({
children,
border,
Expand Down
56 changes: 56 additions & 0 deletions app/src/components/ui/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react";

import { cn } from "@/components/ui/lib/utils";

const Accordion = AccordionPrimitive.Root;

const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
));
AccordionItem.displayName = "AccordionItem";

const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all [&[data-state=open]>svg]:rotate-180",
className,
)}
{...props}
>
{children}
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;

const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
));

AccordionContent.displayName = AccordionPrimitive.Content.displayName;

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
11 changes: 9 additions & 2 deletions app/src/components/ui/textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,21 @@ export interface FlexibleTextareaProps extends TextareaProps {
const FlexibleTextarea = React.forwardRef<
HTMLTextAreaElement,
FlexibleTextareaProps
>(({ rows = 1, ...props }, ref) => {
>(({ rows = 1, className, ...props }, ref) => {
const lines = useMemo(() => {
const value = props.value?.toString() || "";
const count = value.split("\n").length + 1;
return Math.max(rows, count);
}, [props.value]);

return <Textarea ref={ref} rows={lines} {...props} />;
return (
<Textarea
className={cn("resize-none no-scrollbar", className)}
ref={ref}
rows={lines}
{...props}
/>
);
});

FlexibleTextarea.displayName = "FlexibleTextarea";
Expand Down
10 changes: 5 additions & 5 deletions app/src/routes/admin/System.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
import { DialogTitle } from "@radix-ui/react-dialog";
import Require from "@/components/Require.tsx";
import { Loader2, Settings2 } from "lucide-react";
import { Textarea } from "@/components/ui/textarea.tsx";
import { FlexibleTextarea } from "@/components/ui/textarea.tsx";
import Tips from "@/components/Tips.tsx";
import { cn } from "@/components/ui/lib/utils.ts";
import { Switch } from "@/components/ui/switch.tsx";
Expand Down Expand Up @@ -527,7 +527,7 @@ function Site({ data, dispatch, onChange }: CompProps<SiteState>) {
</ParagraphItem>
<ParagraphItem rowLayout={true}>
<Label>{t("admin.system.announcement")}</Label>
<Textarea
<FlexibleTextarea
value={data.announcement}
rows={12}
onChange={(e) =>
Expand All @@ -541,7 +541,7 @@ function Site({ data, dispatch, onChange }: CompProps<SiteState>) {
</ParagraphItem>
<ParagraphItem rowLayout={true}>
<Label>{t("admin.system.contact")}</Label>
<Textarea
<FlexibleTextarea
value={data.contact}
rows={6}
onChange={(e) =>
Expand All @@ -556,9 +556,9 @@ function Site({ data, dispatch, onChange }: CompProps<SiteState>) {
<ParagraphSpace />
<ParagraphItem rowLayout={true}>
<Label>{t("admin.system.footer")}</Label>
<Textarea
value={data.footer}
<FlexibleTextarea
rows={6}
value={data.footer}
onChange={(e) =>
dispatch({
type: "update:site.footer",
Expand Down

0 comments on commit 82d0f3c

Please sign in to comment.