Various UX & Chat improvements
This commit is contained in:
parent
6ea3c10fd5
commit
6b96db8cfe
11 changed files with 229 additions and 221 deletions
|
|
@ -10,12 +10,10 @@ import { legalDocsSchema } from "@tensamin/shared/features/legal/schema";
|
||||||
import { log } from "@tensamin/shared/log";
|
import { log } from "@tensamin/shared/log";
|
||||||
import Link from "@tensamin/ui/link";
|
import Link from "@tensamin/ui/link";
|
||||||
import { Label } from "@tensamin/ui/cmp/label";
|
import { Label } from "@tensamin/ui/cmp/label";
|
||||||
import { useLocation } from "@tanstack/react-router";
|
|
||||||
|
|
||||||
// Prevents the user from using Tensamin without accepting the privacy policy and terms of service.
|
// Prevents the user from using Tensamin without accepting the privacy policy and terms of service.
|
||||||
export default function Screen(props: { children: React.ReactNode }) {
|
export default function Screen(props: { children: React.ReactNode }) {
|
||||||
const { load, save } = useStorage();
|
const { load, save } = useStorage();
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [errorDescription, setErrorDescription] = useState("");
|
const [errorDescription, setErrorDescription] = useState("");
|
||||||
|
|
@ -138,7 +136,7 @@ export default function Screen(props: { children: React.ReactNode }) {
|
||||||
return () => {
|
return () => {
|
||||||
active = false;
|
active = false;
|
||||||
};
|
};
|
||||||
}, [load, location.pathname]);
|
}, [load]);
|
||||||
|
|
||||||
if (error !== "" && errorDescription !== "") {
|
if (error !== "" && errorDescription !== "") {
|
||||||
return <ErrorScreen error={error} description={errorDescription} />;
|
return <ErrorScreen error={error} description={errorDescription} />;
|
||||||
|
|
|
||||||
|
|
@ -7,64 +7,40 @@
|
||||||
@source "./**/*.{ts,tsx}";
|
@source "./**/*.{ts,tsx}";
|
||||||
@source "../../../packages/**/src/**/*.{ts,tsx}";
|
@source "../../../packages/**/src/**/*.{ts,tsx}";
|
||||||
|
|
||||||
:root {
|
|
||||||
--text: #121212;
|
|
||||||
--background: #f2f2f2;
|
|
||||||
--primary: #00786f;
|
|
||||||
--secondary: #338788;
|
|
||||||
--accent: #13b9a0;
|
|
||||||
--radius: 0.625rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
--text: #eeeeee;
|
|
||||||
--background: #0c0c0c;
|
|
||||||
--primary: #005f5a;
|
|
||||||
--secondary: #0b3134;
|
|
||||||
--accent: #46ecd4;
|
|
||||||
--radius: 0.625rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
|
--font-heading: var(--font-sans);
|
||||||
--font-sans: "Inter Variable", sans-serif;
|
--font-sans: "Inter Variable", sans-serif;
|
||||||
|
--color-sidebar-ring: var(--sidebar-ring);
|
||||||
--color-background: var(--background);
|
--color-sidebar-border: var(--sidebar-border);
|
||||||
--color-foreground: var(--text);
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||||
|
--color-sidebar-accent: var(--sidebar-accent);
|
||||||
--color-primary: var(--primary);
|
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||||
--color-primary-foreground: var(--text);
|
--color-sidebar-primary: var(--sidebar-primary);
|
||||||
--color-secondary: var(--secondary);
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||||
--color-secondary-foreground: var(--background);
|
--color-sidebar: var(--sidebar);
|
||||||
|
--color-chart-5: var(--chart-5);
|
||||||
|
--color-chart-4: var(--chart-4);
|
||||||
|
--color-chart-3: var(--chart-3);
|
||||||
|
--color-chart-2: var(--chart-2);
|
||||||
|
--color-chart-1: var(--chart-1);
|
||||||
|
--color-ring: var(--ring);
|
||||||
|
--color-input: var(--input);
|
||||||
|
--color-border: var(--border);
|
||||||
|
--color-destructive: var(--destructive);
|
||||||
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
--color-accent: var(--accent);
|
--color-accent: var(--accent);
|
||||||
--color-accent-foreground: var(--background);
|
--color-muted-foreground: var(--muted-foreground);
|
||||||
|
--color-muted: var(--muted);
|
||||||
--color-muted: color-mix(in srgb, var(--text) 20%, var(--background));
|
--color-secondary-foreground: var(--secondary-foreground);
|
||||||
--color-muted-foreground: var(--text);
|
--color-secondary: var(--secondary);
|
||||||
--color-border: color-mix(in srgb, var(--text) 13%, var(--background));
|
--color-primary-foreground: var(--primary-foreground);
|
||||||
--color-input: color-mix(in srgb, var(--text) 15%, var(--background));
|
--color-primary: var(--primary);
|
||||||
--color-ring: color-mix(in srgb, var(--text) 45%, var(--background));
|
--color-popover-foreground: var(--popover-foreground);
|
||||||
--color-destructive: hsl(0 84% 60%);
|
--color-popover: var(--popover);
|
||||||
|
--color-card-foreground: var(--card-foreground);
|
||||||
--color-card: color-mix(in srgb, var(--text) 6%, var(--background));
|
--color-card: var(--card);
|
||||||
--color-card-foreground: var(--text);
|
--color-foreground: var(--foreground);
|
||||||
--color-popover: color-mix(in srgb, var(--text) 5%, var(--background));
|
--color-background: var(--background);
|
||||||
--color-popover-foreground: var(--text);
|
|
||||||
|
|
||||||
--color-sidebar: color-mix(in srgb, var(--text) 3%, var(--background));
|
|
||||||
--color-sidebar-foreground: var(--text);
|
|
||||||
--color-sidebar-primary: var(--primary);
|
|
||||||
--color-sidebar-primary-foreground: var(--background);
|
|
||||||
--color-sidebar-accent: var(--accent);
|
|
||||||
--color-sidebar-accent-foreground: var(--background);
|
|
||||||
--color-sidebar-border: var(--border);
|
|
||||||
--color-sidebar-ring: var(--primary);
|
|
||||||
|
|
||||||
--color-chart-1: var(--primary);
|
|
||||||
--color-chart-2: var(--secondary);
|
|
||||||
--color-chart-3: var(--accent);
|
|
||||||
--color-chart-4: color-mix(in srgb, var(--primary) 70%, white);
|
|
||||||
--color-chart-5: color-mix(in srgb, var(--secondary) 70%, white);
|
|
||||||
|
|
||||||
--radius-sm: calc(var(--radius) * 0.6);
|
--radius-sm: calc(var(--radius) * 0.6);
|
||||||
--radius-md: calc(var(--radius) * 0.8);
|
--radius-md: calc(var(--radius) * 0.8);
|
||||||
--radius-lg: var(--radius);
|
--radius-lg: var(--radius);
|
||||||
|
|
@ -74,6 +50,75 @@
|
||||||
--radius-4xl: calc(var(--radius) * 2.6);
|
--radius-4xl: calc(var(--radius) * 2.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: oklch(1 0 0);
|
||||||
|
--foreground: oklch(0.145 0 0);
|
||||||
|
--card: oklch(1 0 0);
|
||||||
|
--card-foreground: oklch(0.145 0 0);
|
||||||
|
--popover: oklch(1 0 0);
|
||||||
|
--popover-foreground: oklch(0.145 0 0);
|
||||||
|
--primary: oklch(0.511 0.096 186.391);
|
||||||
|
--primary-foreground: oklch(0.984 0.014 180.72);
|
||||||
|
--secondary: oklch(0.967 0.001 286.375);
|
||||||
|
--secondary-foreground: oklch(0.21 0.006 285.885);
|
||||||
|
--muted: oklch(0.97 0 0);
|
||||||
|
--muted-foreground: oklch(0.556 0 0);
|
||||||
|
--accent: oklch(0.97 0 0);
|
||||||
|
--accent-foreground: oklch(0.205 0 0);
|
||||||
|
--destructive: oklch(0.577 0.245 27.325);
|
||||||
|
--border: oklch(0.922 0 0);
|
||||||
|
--input: oklch(0.922 0 0);
|
||||||
|
--ring: oklch(0.708 0 0);
|
||||||
|
--chart-1: oklch(0.855 0.138 181.071);
|
||||||
|
--chart-2: oklch(0.704 0.14 182.503);
|
||||||
|
--chart-3: oklch(0.6 0.118 184.704);
|
||||||
|
--chart-4: oklch(0.511 0.096 186.391);
|
||||||
|
--chart-5: oklch(0.437 0.078 188.216);
|
||||||
|
--radius: 0.625rem;
|
||||||
|
--sidebar: oklch(0.985 0 0);
|
||||||
|
--sidebar-foreground: oklch(0.145 0 0);
|
||||||
|
--sidebar-primary: oklch(0.6 0.118 184.704);
|
||||||
|
--sidebar-primary-foreground: oklch(0.984 0.014 180.72);
|
||||||
|
--sidebar-accent: oklch(0.97 0 0);
|
||||||
|
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||||
|
--sidebar-border: oklch(0.922 0 0);
|
||||||
|
--sidebar-ring: oklch(0.708 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: oklch(0.145 0 0);
|
||||||
|
--foreground: oklch(0.985 0 0);
|
||||||
|
--card: oklch(0.225 0 0);
|
||||||
|
--card-foreground: oklch(0.985 0 0);
|
||||||
|
--popover: oklch(0.205 0 0);
|
||||||
|
--popover-foreground: oklch(0.985 0 0);
|
||||||
|
--primary: oklch(0.437 0.078 188.216);
|
||||||
|
--primary-foreground: oklch(0.984 0.014 180.72);
|
||||||
|
--secondary: oklch(0.274 0.006 286.033);
|
||||||
|
--secondary-foreground: oklch(0.985 0 0);
|
||||||
|
--muted: oklch(0.269 0 0);
|
||||||
|
--muted-foreground: oklch(0.708 0 0);
|
||||||
|
--accent: oklch(0.269 0 0);
|
||||||
|
--accent-foreground: oklch(0.985 0 0);
|
||||||
|
--destructive: oklch(0.704 0.191 22.216);
|
||||||
|
--border: oklch(1 0 0 / 10%);
|
||||||
|
--input: oklch(1 0 0 / 15%);
|
||||||
|
--ring: oklch(0.556 0 0);
|
||||||
|
--chart-1: oklch(0.855 0.138 181.071);
|
||||||
|
--chart-2: oklch(0.704 0.14 182.503);
|
||||||
|
--chart-3: oklch(0.6 0.118 184.704);
|
||||||
|
--chart-4: oklch(0.511 0.096 186.391);
|
||||||
|
--chart-5: oklch(0.437 0.078 188.216);
|
||||||
|
--sidebar: oklch(0.190 0 0);
|
||||||
|
--sidebar-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-primary: oklch(0.704 0.14 182.503);
|
||||||
|
--sidebar-primary-foreground: oklch(0.277 0.046 192.524);
|
||||||
|
--sidebar-accent: oklch(0.269 0 0);
|
||||||
|
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||||
|
--sidebar-border: oklch(1 0 0 / 10%);
|
||||||
|
--sidebar-ring: oklch(0.556 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
|
|
@ -92,4 +137,13 @@
|
||||||
background: var(--color-primary, var(--primary));
|
background: var(--color-primary, var(--primary));
|
||||||
color: var(--color-primary-foreground, var(--primary-foreground));
|
color: var(--color-primary-foreground, var(--primary-foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selection-foreground {
|
||||||
|
::selection {
|
||||||
|
@apply bg-foreground/65 text-background;
|
||||||
|
}
|
||||||
|
::-moz-selection {
|
||||||
|
@apply bg-foreground/65 text-background;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ function LoginWrapper({ children }: { children: ReactNode }) {
|
||||||
return () => {
|
return () => {
|
||||||
active = false;
|
active = false;
|
||||||
};
|
};
|
||||||
}, [load, navigate, location.pathname]);
|
}, [load, navigate]);
|
||||||
|
|
||||||
if (loggedIn !== true && location.pathname !== "/login") {
|
if (loggedIn !== true && location.pathname !== "/login") {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { useChat } from "../context";
|
||||||
import { useTTP } from "@tensamin/ttp/context";
|
import { useTTP } from "@tensamin/ttp/context";
|
||||||
import { useCrypto } from "@tensamin/crypto/context";
|
import { useCrypto } from "@tensamin/crypto/context";
|
||||||
import { log, toast } from "@tensamin/shared/log";
|
import { log, toast } from "@tensamin/shared/log";
|
||||||
|
import Message from "./message";
|
||||||
|
|
||||||
export default function InputComponent({
|
export default function InputComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -18,6 +19,7 @@ export default function InputComponent({
|
||||||
setValue: (value: string) => void;
|
setValue: (value: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const [invertEnterBehavior, setInvertEnterBehavior] = React.useState(false);
|
const [invertEnterBehavior, setInvertEnterBehavior] = React.useState(false);
|
||||||
|
const measurementRef = React.useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const { encrypt } = useCrypto();
|
const { encrypt } = useCrypto();
|
||||||
const { send } = useTTP();
|
const { send } = useTTP();
|
||||||
|
|
@ -30,6 +32,21 @@ export default function InputComponent({
|
||||||
});
|
});
|
||||||
}, [load]);
|
}, [load]);
|
||||||
|
|
||||||
|
const getRenderedHeight = React.useCallback(() => {
|
||||||
|
const measuredHeight =
|
||||||
|
measurementRef.current?.getBoundingClientRect().height;
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof measuredHeight === "number" &&
|
||||||
|
Number.isFinite(measuredHeight) &&
|
||||||
|
measuredHeight > 0
|
||||||
|
) {
|
||||||
|
return Math.ceil(measuredHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 40;
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes handleSubmit.
|
* Executes handleSubmit.
|
||||||
* @param none This function has no parameters.
|
* @param none This function has no parameters.
|
||||||
|
|
@ -51,7 +68,7 @@ export default function InputComponent({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const height = currentValue.split("\n").length * 24 + 16; // 24px per line + 16px padding
|
const height = getRenderedHeight();
|
||||||
|
|
||||||
const reference = addLiveMessage({
|
const reference = addLiveMessage({
|
||||||
height,
|
height,
|
||||||
|
|
@ -85,7 +102,25 @@ export default function InputComponent({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="rounded-none rounded-t-xl border-b-0 pt-0 pb-[env(safe-area-inset-bottom)]">
|
<Card className="rounded-none rounded-t-xl border-b-0 pt-0 pb-[env(safe-area-inset-bottom)]">
|
||||||
<CardHeader className="p-0 flex flex-col">
|
<CardHeader className="relative p-0 flex flex-col">
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="pointer-events-none absolute left-0 top-0 w-full opacity-0"
|
||||||
|
style={{ visibility: "hidden" }}
|
||||||
|
>
|
||||||
|
<Message
|
||||||
|
measureRef={measurementRef}
|
||||||
|
message={{
|
||||||
|
height: 0,
|
||||||
|
not_encrypted: true,
|
||||||
|
timestamp: 0,
|
||||||
|
content: value,
|
||||||
|
sent_by_self: true,
|
||||||
|
message_state: "awaiting",
|
||||||
|
}}
|
||||||
|
notEncrypted
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Input
|
<Input
|
||||||
placeholder="Send a message..."
|
placeholder="Send a message..."
|
||||||
value={value}
|
value={value}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,17 @@ import {
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@tensamin/ui/cmp/tooltip";
|
} from "@tensamin/ui/cmp/tooltip";
|
||||||
|
import { useIsMobile } from "@tensamin/ui/utils";
|
||||||
|
import {
|
||||||
|
ContextMenu,
|
||||||
|
ContextMenuContent,
|
||||||
|
ContextMenuItem,
|
||||||
|
ContextMenuTrigger,
|
||||||
|
} from "@tensamin/ui/cmp/context-menu";
|
||||||
|
|
||||||
|
function generateFixedLoadingSize(size: number, height: number) {
|
||||||
|
return size * 3 - (height / 20) * 11;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes Message.
|
* Executes Message.
|
||||||
|
|
@ -22,10 +33,13 @@ export default function Message(props: {
|
||||||
failed?: boolean;
|
failed?: boolean;
|
||||||
};
|
};
|
||||||
notEncrypted?: boolean;
|
notEncrypted?: boolean;
|
||||||
|
measureRef?: React.Ref<HTMLDivElement>;
|
||||||
}) {
|
}) {
|
||||||
const { sharedSecret } = useChat();
|
const { sharedSecret } = useChat();
|
||||||
const { decrypt } = useCrypto();
|
const { decrypt } = useCrypto();
|
||||||
|
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
const [decodedContent, setDecodedContent] = React.useState("");
|
const [decodedContent, setDecodedContent] = React.useState("");
|
||||||
const [isReady, setIsReady] = React.useState(false);
|
const [isReady, setIsReady] = React.useState(false);
|
||||||
|
|
||||||
|
|
@ -75,38 +89,57 @@ export default function Message(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={props.measureRef}
|
||||||
className={`w-full flex justify-start transition-opacity duration-150 ${(props.message.failed || props.message.message_state === "awaiting") && "opacity-50"}`}
|
className={`w-full flex justify-start transition-opacity duration-150 ${(props.message.failed || props.message.message_state === "awaiting") && "opacity-50"}`}
|
||||||
>
|
>
|
||||||
<div
|
<ContextMenu>
|
||||||
className={`flex gap-1 items-center justify-center max-w-[80%] rounded-lg px-2 py-px whitespace-pre-wrap wrap-break-word ${
|
<ContextMenuTrigger
|
||||||
props.message.sent_by_self
|
render={
|
||||||
? props.message.failed
|
<div
|
||||||
? "bg-destructive/75 text-destructive-foreground"
|
className={`selection-foreground flex gap-1 items-center justify-center max-w-[80%] rounded-lg px-2 py-px whitespace-pre-wrap break-all ${
|
||||||
: "bg-primary text-primary-foreground"
|
props.message.sent_by_self
|
||||||
: "bg-muted"
|
? props.message.failed
|
||||||
} ${!isReady && "animate-pulse"}`}
|
? "bg-destructive/75 text-destructive-foreground"
|
||||||
>
|
: "bg-primary text-primary-foreground"
|
||||||
{props.message.failed && props.message.message_state === "awaiting" && (
|
: "bg-muted"
|
||||||
<Tooltip>
|
} ${!isReady && "animate-pulse"} ${isMobile && "select-none"}`}
|
||||||
<TooltipContent>
|
>
|
||||||
<p>Failed to send message</p>
|
{props.message.failed &&
|
||||||
</TooltipContent>
|
props.message.message_state === "awaiting" && (
|
||||||
<TooltipTrigger render={<AlertTriangle size={17} />} />
|
<Tooltip>
|
||||||
</Tooltip>
|
<TooltipContent>
|
||||||
)}
|
<p>Failed to send message</p>
|
||||||
{!props.message.failed &&
|
</TooltipContent>
|
||||||
props.message.message_state === "awaiting" && <Clock size={17} />}
|
<TooltipTrigger render={<AlertTriangle size={17} />} />
|
||||||
{isReady ? (
|
</Tooltip>
|
||||||
<Text value={decodedContent} />
|
)}
|
||||||
) : (
|
{!props.message.failed &&
|
||||||
<div
|
props.message.message_state === "awaiting" && (
|
||||||
className="h-8"
|
<Clock size={17} />
|
||||||
style={{
|
)}
|
||||||
width: Math.random() * 100 + 50 + "px",
|
{isReady ? (
|
||||||
}}
|
<Text value={decodedContent} />
|
||||||
/>
|
) : (
|
||||||
)}
|
<div
|
||||||
</div>
|
className="h-8"
|
||||||
|
style={{
|
||||||
|
width: generateFixedLoadingSize(
|
||||||
|
props.message.content.length,
|
||||||
|
props.message.height,
|
||||||
|
),
|
||||||
|
height: props.message.height,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ContextMenuContent>
|
||||||
|
<ContextMenuItem>
|
||||||
|
<Text value={decodedContent} />
|
||||||
|
</ContextMenuItem>
|
||||||
|
</ContextMenuContent>
|
||||||
|
</ContextMenu>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ export default function Screen() {
|
||||||
window.innerHeight,
|
window.innerHeight,
|
||||||
window.visualViewport?.height ?? 0,
|
window.visualViewport?.height ?? 0,
|
||||||
);
|
);
|
||||||
const inputHeight = el.scrollHeight + 50;
|
const inputHeight = el.scrollHeight + 56;
|
||||||
|
|
||||||
host.style.maxHeight = `calc(${viewportHeight}px - ${inputHeight}px - env(safe-area-inset-bottom) - env(safe-area-inset-top))`;
|
host.style.maxHeight = `calc(${viewportHeight}px - ${inputHeight}px - env(safe-area-inset-bottom) - env(safe-area-inset-top))`;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
||||||
|
|
@ -637,8 +637,7 @@ function readTable(
|
||||||
}
|
}
|
||||||
|
|
||||||
export const markdownStyles = `
|
export const markdownStyles = `
|
||||||
.tm-md-root { color: var(--foreground); line-height: 1.55; font-size: 0.95rem; }
|
.tm-md-root { color: hsl(var(--foreground)); line-height: 1.55; font-size: 0.95rem; }
|
||||||
.tm-md-root * { box-sizing: border-box; }
|
|
||||||
.tm-md-heading { margin: 0.2rem 0 0.35rem; font-weight: 700; line-height: 1.25; }
|
.tm-md-heading { margin: 0.2rem 0 0.35rem; font-weight: 700; line-height: 1.25; }
|
||||||
.tm-md-h1 { font-size: 1.65rem; }
|
.tm-md-h1 { font-size: 1.65rem; }
|
||||||
.tm-md-h2 { font-size: 1.45rem; }
|
.tm-md-h2 { font-size: 1.45rem; }
|
||||||
|
|
@ -647,33 +646,33 @@ export const markdownStyles = `
|
||||||
.tm-md-h5 { font-size: 1rem; }
|
.tm-md-h5 { font-size: 1rem; }
|
||||||
.tm-md-h6 { font-size: 0.95rem; opacity: 0.9; }
|
.tm-md-h6 { font-size: 0.95rem; opacity: 0.9; }
|
||||||
.tm-md-p { margin: 0.25rem 0; }
|
.tm-md-p { margin: 0.25rem 0; }
|
||||||
.tm-md-blockquote { margin: 0.45rem 0; padding-left: 0.75rem; border-left: 2px solid var(--border); opacity: 0.95; }
|
.tm-md-blockquote { margin: 0.45rem 0; padding-left: 0.75rem; opacity: 0.95; }
|
||||||
.tm-md-blockquote p { margin: 0.2rem 0; }
|
.tm-md-blockquote p { margin: 0.2rem 0; }
|
||||||
.tm-md-pre { margin: 0.45rem 0; padding: 0.65rem 0.75rem; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--muted); overflow-x: auto; }
|
.tm-md-pre { margin: 0.45rem 0; padding: 0.65rem 0.75rem; border-radius: 0.5rem; background: hsl(var(--muted)); overflow-x: auto; }
|
||||||
.tm-md-code, .tm-md-codeblock { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
|
.tm-md-code, .tm-md-codeblock { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
|
||||||
.tm-md-code { padding: 0.08rem 0.32rem; border-radius: 0.28rem; background: var(--muted); }
|
.tm-md-code { padding: 0.08rem 0.32rem; border-radius: 0.28rem; background: hsl(var(--muted)); }
|
||||||
.tm-md-strong { font-weight: 700; }
|
.tm-md-strong { font-weight: 700; }
|
||||||
.tm-md-em { font-style: italic; }
|
.tm-md-em { font-style: italic; }
|
||||||
.tm-md-del { text-decoration: line-through; }
|
.tm-md-del { text-decoration: line-through; }
|
||||||
.tm-md-link { color: var(--primary); text-decoration: underline; text-underline-offset: 0.14rem; }
|
.tm-md-link { color: hsl(var(--primary)); text-decoration: underline; text-underline-offset: 0.14rem; }
|
||||||
.tm-md-image { display: block; max-width: 100%; border-radius: 0.4rem; margin: 0.5rem 0; }
|
.tm-md-image { display: block; max-width: 100%; border-radius: 0.4rem; margin: 0.5rem 0; }
|
||||||
.tm-md-ul, .tm-md-ol { margin: 0.3rem 0 0.35rem 1.2rem; padding: 0; }
|
.tm-md-ul, .tm-md-ol { margin: 0.3rem 0 0.35rem 1.2rem; padding: 0; }
|
||||||
.tm-md-li { margin: 0.2rem 0; }
|
.tm-md-li { margin: 0.2rem 0; }
|
||||||
.tm-md-checkbox { margin-right: 0.5rem; vertical-align: middle; }
|
.tm-md-checkbox { margin-right: 0.5rem; vertical-align: middle; }
|
||||||
.tm-md-table-wrap { overflow-x: auto; margin: 0.45rem 0; }
|
.tm-md-table-wrap { overflow-x: auto; margin: 0.45rem 0; }
|
||||||
.tm-md-table { border-collapse: collapse; width: 100%; min-width: 16rem; }
|
.tm-md-table { border-collapse: collapse; width: 100%; min-width: 16rem; }
|
||||||
.tm-md-table th, .tm-md-table td { border: 1px solid var(--border); padding: 0.4rem 0.5rem; text-align: left; }
|
.tm-md-table th, .tm-md-table td { padding: 0.4rem 0.5rem; text-align: left; }
|
||||||
.tm-md-table th { background: var(--muted); font-weight: 600; }
|
.tm-md-table th { background: hsl(var(--muted)); font-weight: 600; }
|
||||||
.tm-md-hr { border: 0; border-top: 1px solid var(--border); margin: 0.55rem 0; }
|
.tm-md-hr { margin: 0.55rem 0; }
|
||||||
|
|
||||||
.cm-editor.tm-md-editor { border: 1px solid var(--border); border-radius: 0.65rem; background: var(--card); }
|
.cm-editor.tm-md-editor { border-radius: 0.65rem; background: hsl(var(--card)); caret-color: var(--foreground); }
|
||||||
.cm-editor.tm-md-editor.cm-focused { outline: 2px solid var(--ring); outline-offset: 1px; }
|
.cm-editor.tm-md-editor.cm-focused { outline: none; box-shadow: none; }
|
||||||
.cm-editor.tm-md-editor .cm-scroller { font-family: inherit; line-height: 1.55; max-height: 30vh; overflow-y: auto; overflow-x: hidden; }
|
.cm-editor.tm-md-editor .cm-scroller { font-family: inherit; line-height: 1.55; max-height: 30vh; overflow-y: auto; overflow-x: hidden; }
|
||||||
.cm-editor.tm-md-editor .cm-content { caret-color: var(--text); }
|
.cm-editor.tm-md-editor .cm-content { caret-color: var(--foreground); }
|
||||||
.cm-editor.tm-md-editor .cm-content { padding: 0.7rem 0.85rem; min-height: 2.75rem; }
|
.cm-editor.tm-md-editor .cm-content { padding: 0.7rem 0.85rem; min-height: 2.75rem; }
|
||||||
.cm-editor.tm-md-editor .cm-line { padding: 0 1px; color: var(--text); }
|
.cm-editor.tm-md-editor .cm-line { padding: 0 1px; color: hsl(var(--foreground)); }
|
||||||
.cm-editor.tm-md-editor .tm-md-hidden-token { color: transparent; opacity: 0; font-size: inherit; }
|
.cm-editor.tm-md-editor .tm-md-hidden-token { color: transparent; opacity: 0; font-size: inherit; }
|
||||||
.cm-editor.tm-md-editor .tm-md-code-line { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; background: var(--muted); border-radius: 0.3rem; }
|
.cm-editor.tm-md-editor .tm-md-code-line { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; background: hsl(var(--muted)); border-radius: 0.3rem; }
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
"lib": "@/lib",
|
"lib": "@/lib",
|
||||||
"hooks": "@/hooks"
|
"hooks": "@/hooks"
|
||||||
},
|
},
|
||||||
"menuColor": "default-translucent",
|
"menuColor": "default",
|
||||||
"menuAccent": "subtle",
|
"menuAccent": "subtle",
|
||||||
"registries": {}
|
"registries": {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ function ContextMenuContent({
|
||||||
<ContextMenuPrimitive.Popup
|
<ContextMenuPrimitive.Popup
|
||||||
data-slot="context-menu-content"
|
data-slot="context-menu-content"
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 animate-none! relative bg-popover/70 before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:rounded-[inherit] before:backdrop-blur-2xl before:backdrop-saturate-150 **:data-[slot$=-item]:focus:bg-foreground/10 **:data-[slot$=-item]:data-highlighted:bg-foreground/10 **:data-[slot$=-separator]:bg-foreground/5 **:data-[slot$=-trigger]:focus:bg-foreground/10 **:data-[slot$=-trigger]:aria-expanded:bg-foreground/10! **:data-[variant=destructive]:focus:bg-foreground/10! **:data-[variant=destructive]:text-accent-foreground! **:data-[variant=destructive]:**:text-accent-foreground!",
|
"z-50 max-h-(--available-height) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -148,7 +148,7 @@ function ContextMenuSubContent({
|
||||||
return (
|
return (
|
||||||
<ContextMenuContent
|
<ContextMenuContent
|
||||||
data-slot="context-menu-sub-content"
|
data-slot="context-menu-sub-content"
|
||||||
className="shadow-lg animate-none! relative bg-popover/70 before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:rounded-[inherit] before:backdrop-blur-2xl before:backdrop-saturate-150 **:data-[slot$=-item]:focus:bg-foreground/10 **:data-[slot$=-item]:data-highlighted:bg-foreground/10 **:data-[slot$=-separator]:bg-foreground/5 **:data-[slot$=-trigger]:focus:bg-foreground/10 **:data-[slot$=-trigger]:aria-expanded:bg-foreground/10! **:data-[variant=destructive]:focus:bg-foreground/10! **:data-[variant=destructive]:text-accent-foreground! **:data-[variant=destructive]:**:text-accent-foreground!"
|
className="shadow-lg"
|
||||||
side="right"
|
side="right"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ function SelectContent({
|
||||||
data-slot="select-content"
|
data-slot="select-content"
|
||||||
data-align-trigger={alignItemWithTrigger}
|
data-align-trigger={alignItemWithTrigger}
|
||||||
className={cn(
|
className={cn(
|
||||||
"isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 animate-none! relative bg-popover/70 before:pointer-events-none before:absolute before:inset-0 before:-z-1 before:rounded-[inherit] before:backdrop-blur-2xl before:backdrop-saturate-150 **:data-[slot$=-item]:focus:bg-foreground/10 **:data-[slot$=-item]:data-highlighted:bg-foreground/10 **:data-[slot$=-separator]:bg-foreground/5 **:data-[slot$=-trigger]:focus:bg-foreground/10 **:data-[slot$=-trigger]:aria-expanded:bg-foreground/10! **:data-[variant=destructive]:focus:bg-foreground/10! **:data-[variant=destructive]:text-accent-foreground! **:data-[variant=destructive]:**:text-accent-foreground!",
|
"relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
||||||
|
|
@ -5,117 +5,6 @@
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
:root {
|
|
||||||
--background: oklch(1 0 0);
|
|
||||||
--foreground: oklch(0.148 0.004 228.8);
|
|
||||||
--card: oklch(1 0 0);
|
|
||||||
--card-foreground: oklch(0.148 0.004 228.8);
|
|
||||||
--popover: oklch(1 0 0);
|
|
||||||
--popover-foreground: oklch(0.148 0.004 228.8);
|
|
||||||
--primary: oklch(0.511 0.096 186.391);
|
|
||||||
--primary-foreground: oklch(0.984 0.014 180.72);
|
|
||||||
--secondary: oklch(0.967 0.001 286.375);
|
|
||||||
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
||||||
--muted: oklch(0.963 0.002 197.1);
|
|
||||||
--muted-foreground: oklch(0.56 0.021 213.5);
|
|
||||||
--accent: oklch(0.963 0.002 197.1);
|
|
||||||
--accent-foreground: oklch(0.218 0.008 223.9);
|
|
||||||
--destructive: oklch(0.577 0.245 27.325);
|
|
||||||
--border: oklch(0.925 0.005 214.3);
|
|
||||||
--input: oklch(0.925 0.005 214.3);
|
|
||||||
--ring: oklch(0.723 0.014 214.4);
|
|
||||||
--chart-1: oklch(0.855 0.138 181.071);
|
|
||||||
--chart-2: oklch(0.704 0.14 182.503);
|
|
||||||
--chart-3: oklch(0.6 0.118 184.704);
|
|
||||||
--chart-4: oklch(0.511 0.096 186.391);
|
|
||||||
--chart-5: oklch(0.437 0.078 188.216);
|
|
||||||
--radius: 0.625rem;
|
|
||||||
--sidebar: oklch(0.987 0.002 197.1);
|
|
||||||
--sidebar-foreground: oklch(0.148 0.004 228.8);
|
|
||||||
--sidebar-primary: oklch(0.6 0.118 184.704);
|
|
||||||
--sidebar-primary-foreground: oklch(0.984 0.014 180.72);
|
|
||||||
--sidebar-accent: oklch(0.963 0.002 197.1);
|
|
||||||
--sidebar-accent-foreground: oklch(0.218 0.008 223.9);
|
|
||||||
--sidebar-border: oklch(0.925 0.005 214.3);
|
|
||||||
--sidebar-ring: oklch(0.723 0.014 214.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
--background: oklch(0.148 0.004 228.8);
|
|
||||||
--foreground: oklch(0.987 0.002 197.1);
|
|
||||||
--card: oklch(0.218 0.008 223.9);
|
|
||||||
--card-foreground: oklch(0.987 0.002 197.1);
|
|
||||||
--popover: oklch(0.218 0.008 223.9);
|
|
||||||
--popover-foreground: oklch(0.987 0.002 197.1);
|
|
||||||
--primary: oklch(0.437 0.078 188.216);
|
|
||||||
--primary-foreground: oklch(0.984 0.014 180.72);
|
|
||||||
--secondary: oklch(0.274 0.006 286.033);
|
|
||||||
--secondary-foreground: oklch(0.985 0 0);
|
|
||||||
--muted: oklch(0.275 0.011 216.9);
|
|
||||||
--muted-foreground: oklch(0.723 0.014 214.4);
|
|
||||||
--accent: oklch(0.275 0.011 216.9);
|
|
||||||
--accent-foreground: oklch(0.987 0.002 197.1);
|
|
||||||
--destructive: oklch(0.704 0.191 22.216);
|
|
||||||
--border: oklch(1 0 0 / 10%);
|
|
||||||
--input: oklch(1 0 0 / 15%);
|
|
||||||
--ring: oklch(0.56 0.021 213.5);
|
|
||||||
--chart-1: oklch(0.855 0.138 181.071);
|
|
||||||
--chart-2: oklch(0.704 0.14 182.503);
|
|
||||||
--chart-3: oklch(0.6 0.118 184.704);
|
|
||||||
--chart-4: oklch(0.511 0.096 186.391);
|
|
||||||
--chart-5: oklch(0.437 0.078 188.216);
|
|
||||||
--sidebar: oklch(0.218 0.008 223.9);
|
|
||||||
--sidebar-foreground: oklch(0.987 0.002 197.1);
|
|
||||||
--sidebar-primary: oklch(0.704 0.14 182.503);
|
|
||||||
--sidebar-primary-foreground: oklch(0.277 0.046 192.524);
|
|
||||||
--sidebar-accent: oklch(0.275 0.011 216.9);
|
|
||||||
--sidebar-accent-foreground: oklch(0.987 0.002 197.1);
|
|
||||||
--sidebar-border: oklch(1 0 0 / 10%);
|
|
||||||
--sidebar-ring: oklch(0.56 0.021 213.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
@theme inline {
|
|
||||||
--font-sans: "Inter Variable", sans-serif;
|
|
||||||
--color-sidebar-ring: var(--sidebar-ring);
|
|
||||||
--color-sidebar-border: var(--sidebar-border);
|
|
||||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
||||||
--color-sidebar-accent: var(--sidebar-accent);
|
|
||||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
||||||
--color-sidebar-primary: var(--sidebar-primary);
|
|
||||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
||||||
--color-sidebar: var(--sidebar);
|
|
||||||
--color-chart-5: var(--chart-5);
|
|
||||||
--color-chart-4: var(--chart-4);
|
|
||||||
--color-chart-3: var(--chart-3);
|
|
||||||
--color-chart-2: var(--chart-2);
|
|
||||||
--color-chart-1: var(--chart-1);
|
|
||||||
--color-ring: var(--ring);
|
|
||||||
--color-input: var(--input);
|
|
||||||
--color-border: var(--border);
|
|
||||||
--color-destructive: var(--destructive);
|
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
|
||||||
--color-accent: var(--accent);
|
|
||||||
--color-muted-foreground: var(--muted-foreground);
|
|
||||||
--color-muted: var(--muted);
|
|
||||||
--color-secondary-foreground: var(--secondary-foreground);
|
|
||||||
--color-secondary: var(--secondary);
|
|
||||||
--color-primary-foreground: var(--primary-foreground);
|
|
||||||
--color-primary: var(--primary);
|
|
||||||
--color-popover-foreground: var(--popover-foreground);
|
|
||||||
--color-popover: var(--popover);
|
|
||||||
--color-card-foreground: var(--card-foreground);
|
|
||||||
--color-card: var(--card);
|
|
||||||
--color-foreground: var(--foreground);
|
|
||||||
--color-background: var(--background);
|
|
||||||
--radius-sm: calc(var(--radius) * 0.6);
|
|
||||||
--radius-md: calc(var(--radius) * 0.8);
|
|
||||||
--radius-lg: var(--radius);
|
|
||||||
--radius-xl: calc(var(--radius) * 1.4);
|
|
||||||
--radius-2xl: calc(var(--radius) * 1.8);
|
|
||||||
--radius-3xl: calc(var(--radius) * 2.2);
|
|
||||||
--radius-4xl: calc(var(--radius) * 2.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue