Skip to content

Commit afe6746

Browse files
committed
fix: fix shiki overflow
1 parent 84d511f commit afe6746

File tree

4 files changed

+99
-64
lines changed

4 files changed

+99
-64
lines changed

packages/frontend/src/components/layout/input-output.tsx

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import type { MessageDescriptor } from "@lingui/core";
1717
import { msg } from "@lingui/core/macro";
18+
import { useEffect, useRef, useState } from "react";
1819
import ShikiHighlighter, {
1920
createHighlighterCore, // re-exported from shiki/engine/javascript
2021
createOnigurumaEngine,
@@ -50,6 +51,14 @@ export type InputOutputLayoutProps = {
5051
outputBottomBar?: React.ReactNode;
5152
outputProps?: React.ComponentProps<"textarea">;
5253
language?: string;
54+
classNames?: {
55+
// container?: string;
56+
// firstSection?: string;
57+
// firstSectionToolbar?: string;
58+
// secondSection?: string;
59+
// secondSectionToolbar?: string;
60+
outputLanguageContainer?: string;
61+
};
5362
};
5463

5564
const InputOutputLayout = ({
@@ -64,6 +73,7 @@ const InputOutputLayout = ({
6473
outputBottomBar,
6574
outputProps,
6675
language,
76+
classNames,
6777
}: InputOutputLayoutProps) => {
6878
const { theme } = useTheme();
6979
return (
@@ -72,47 +82,61 @@ const InputOutputLayout = ({
7282
firstLabel={inputLabel}
7383
firstToolbar={inputToolbar}
7484
firstContent={
75-
<div className="flex flex-col gap-2 flex-grow">
85+
<div className="flex-grow flex flex-col gap-2">
7686
<Textarea
87+
disableRing
7788
{...inputProps}
7889
className={cn(
79-
"flex-grow border-input text-foreground font-mono text-sm resize-none focus:ring-ring focus:border-ring",
90+
"flex-grow border-input text-foreground font-mono text-sm resize-none overflow-y-auto",
8091
inputProps?.className,
8192
)}
8293
spellCheck="false"
8394
/>
84-
{inputBottombar}
95+
{inputBottombar && <div className="shrink-0">{inputBottombar}</div>}
8596
</div>
8697
}
8798
secondLabel={outputLabel}
8899
secondToolbar={outputToolbar}
89100
secondContent={
90-
<div className="flex flex-col gap-2 flex-grow">
101+
<div className="flex-1 flex flex-col gap-2">
91102
{language ? (
92-
<div className="bg-[#FFFFFF] dark:bg-[#1E1E1E] rounded-md overflow-y-auto border flex-grow border-input text-foreground font-mono text-sm resize-none focus:ring-ring focus:border-ring">
93-
<ShikiHighlighter
94-
highlighter={highlighter}
95-
language={language}
96-
theme={theme === "dark" ? "dark-plus" : "light-plus"}
97-
className="px-3 py-2 select-text"
98-
addDefaultStyles={false}
99-
showLanguage={false}
100-
// biome-ignore lint/correctness/noChildrenProp: string
101-
children={outputProps?.value as string}
102-
/>
103+
<div
104+
className={cn(
105+
"overflow-hidden",
106+
// (3+1)rem is the height of the header and bottom margin
107+
// 2rem is the height of the toolbar
108+
// 2rem is the padding between the toolbar and the content
109+
orientation === "vertical" && "h-[calc(100vh-4rem-2rem-2rem)]",
110+
orientation === "horizontal" &&
111+
"h-[calc(((100vh-4rem-1rem)/2)-4rem)]",
112+
classNames?.outputLanguageContainer,
113+
)}
114+
>
115+
<div className="bg-[#FFFFFF] dark:bg-[#1E1E1E] rounded-md h-full border border-input text-foreground font-mono text-sm resize-none overflow-y-auto">
116+
<ShikiHighlighter
117+
highlighter={highlighter}
118+
language={language}
119+
theme={theme === "dark" ? "dark-plus" : "light-plus"}
120+
className="px-3 py-2 select-text"
121+
addDefaultStyles={false}
122+
showLanguage={false}
123+
// biome-ignore lint/correctness/noChildrenProp: string
124+
children={outputProps?.value as string}
125+
/>
126+
</div>
103127
</div>
104128
) : (
105129
<Textarea
106130
{...outputProps}
107131
className={cn(
108-
"flex-grow border-input text-foreground font-mono text-sm resize-none focus:ring-ring focus:border-ring",
132+
"flex-grow border-input text-foreground font-mono text-sm resize-none focus:ring-ring focus:border-ring overflow-y-auto",
109133
outputProps?.className,
110134
)}
111135
spellCheck="false"
112136
/>
113137
)}
114138

115-
{outputBottomBar}
139+
{outputBottomBar && <div className="shrink-0">{outputBottomBar}</div>}
116140
</div>
117141
}
118142
/>

packages/frontend/src/components/layout/two-section.tsx

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,60 +54,60 @@ const TwoSectionLayout = ({
5454
}: TwoSectionLayoutProps) => {
5555
const { t } = useLingui();
5656
return (
57-
<div className={cn("flex flex-col h-full gap-4", classNames?.container)}>
57+
<div
58+
className={cn(
59+
"grid grid-cols-1 gap-4 h-[calc(100vh-3rem-1rem)]",
60+
orientation === "vertical" && "md:grid-cols-2",
61+
orientation === "horizontal" && "grid-rows-2",
62+
classNames?.container,
63+
)}
64+
>
65+
{/* Input Section */}
5866
<div
5967
className={cn(
60-
"grid grid-cols-1 gap-4 flex-grow",
61-
orientation !== "horizontal" && "md:grid-cols-2",
68+
"flex flex-col gap-2 bg-background/95 p-3 rounded-lg",
69+
classNames?.firstSection,
6270
)}
6371
>
64-
{/* Input Section */}
6572
<div
6673
className={cn(
67-
"flex flex-col gap-2 bg-background/95 p-3 rounded-lg",
68-
classNames?.firstSection,
74+
"flex items-center justify-between gap-2 mb-2",
75+
classNames?.firstSectionToolbar,
6976
)}
7077
>
78+
{firstLabel && (
79+
<Label className="text-sm font-medium text-foreground/80">
80+
{t(firstLabel)}
81+
</Label>
82+
)}
83+
<div className="flex items-center gap-1">{firstToolbar}</div>
84+
</div>
85+
{firstContent}
86+
</div>
87+
88+
{/* Output Section */}
89+
<div
90+
className={cn(
91+
"flex flex-col gap-2 bg-background/95 p-3 rounded-lg",
92+
classNames?.secondSection,
93+
)}
94+
>
95+
{secondToolbar && (
7196
<div
7297
className={cn(
7398
"flex items-center justify-between gap-2 mb-2",
74-
classNames?.firstSectionToolbar,
99+
classNames?.secondSectionToolbar,
75100
)}
76101
>
77-
{firstLabel && (
102+
{secondLabel && (
78103
<Label className="text-sm font-medium text-foreground/80">
79-
{t(firstLabel)}
104+
{t(secondLabel)}
80105
</Label>
81106
)}
82-
<div className="flex items-center gap-1">{firstToolbar}</div>
107+
<div className="flex items-center gap-1">{secondToolbar}</div>
83108
</div>
84-
{firstContent}
85-
</div>
86-
87-
{/* Output Section */}
88-
<div
89-
className={cn(
90-
"flex flex-col gap-2 bg-background/95 p-3 rounded-lg",
91-
classNames?.secondSection,
92-
)}
93-
>
94-
{secondToolbar && (
95-
<div
96-
className={cn(
97-
"flex items-center justify-between gap-2 mb-2",
98-
classNames?.secondSectionToolbar,
99-
)}
100-
>
101-
{secondLabel && (
102-
<Label className="text-sm font-medium text-foreground/80">
103-
{t(secondLabel)}
104-
</Label>
105-
)}
106-
<div className="flex items-center gap-1">{secondToolbar}</div>
107-
</div>
108-
)}
109-
{secondContent}
110-
</div>
109+
)}
110+
{secondContent}
111111
</div>
112112
</div>
113113
);

packages/frontend/src/components/ui/textarea.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ import type * as React from "react";
1717

1818
import { cn } from "@/lib/utils";
1919

20-
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
20+
function Textarea({
21+
className,
22+
disableRing = false,
23+
...props
24+
}: React.ComponentProps<"textarea"> & { disableRing?: boolean }) {
2125
return (
2226
<textarea
2327
data-slot="textarea"
2428
className={cn(
25-
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
29+
"border-input placeholder:text-muted-foreground aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
30+
!disableRing && "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] ",
2631
className,
2732
)}
2833
{...props}

packages/frontend/src/utilities/formatter/json.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -382,15 +382,13 @@ export default function JsonFormatterPage() {
382382
</>
383383
);
384384

385-
const inputBottombar = (
385+
const inputBottombar = error ? (
386386
<div className="flex items-center gap-2 mt-2">
387-
{error && (
388-
<Callout variant="error" className="w-full">
389-
{String(error)}
390-
</Callout>
391-
)}
387+
<Callout variant="error" className="w-full">
388+
{String(error)}
389+
</Callout>
392390
</div>
393-
);
391+
) : null;
394392

395393
const outputToolbar = (
396394
<>
@@ -459,7 +457,7 @@ export default function JsonFormatterPage() {
459457
);
460458

461459
const outputBottomBar = (
462-
<div className="flex items-center gap-2 mt-2">
460+
<div className="flex items-center gap-2">
463461
<Input
464462
type="text"
465463
placeholder="JSON Path (e.g., $.store.book[*].author)"
@@ -502,6 +500,14 @@ export default function JsonFormatterPage() {
502500
placeholder: "Formatted JSON will appear here",
503501
}}
504502
language="json"
503+
// (3+1)rem is the height of the header and bottom margin
504+
// 2rem is the height of the toolbar
505+
// 2rem is the padding between the toolbar and the content
506+
// 2rem is the height of the bottom bar
507+
// 0.5rem is the padding between the content and the bottom bar
508+
classNames={{
509+
outputLanguageContainer: "h-[calc(100vh-4rem-2rem-2rem-2rem-0.5rem)]",
510+
}}
505511
/>
506512
);
507513
}

0 commit comments

Comments
 (0)