Compare commits
5 Commits
6d8076674f
...
e7d38fc565
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7d38fc565 | ||
|
|
e1bfac3da0 | ||
|
|
f4967925a7 | ||
|
|
b01a7390ee | ||
|
|
9f8008b35d |
@ -19,6 +19,7 @@ pub struct UserInfoExternal {
|
|||||||
pub website_url: Option<String>,
|
pub website_url: Option<String>,
|
||||||
pub organization: Option<String>,
|
pub organization: Option<String>,
|
||||||
pub last_sign_in_at: Option<DateTime<Utc>>,
|
pub last_sign_in_at: Option<DateTime<Utc>>,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
|
||||||
pub is_owner: bool,
|
pub is_owner: bool,
|
||||||
pub is_subscribe: bool,
|
pub is_subscribe: bool,
|
||||||
@ -100,6 +101,7 @@ impl AppService {
|
|||||||
website_url: user.website_url,
|
website_url: user.website_url,
|
||||||
organization: user.organization,
|
organization: user.organization,
|
||||||
last_sign_in_at: user.last_sign_in_at,
|
last_sign_in_at: user.last_sign_in_at,
|
||||||
|
created_at: user.created_at,
|
||||||
is_owner: context.user().map(|u| u == user.uid).unwrap_or(false),
|
is_owner: context.user().map(|u| u == user.uid).unwrap_or(false),
|
||||||
is_subscribe,
|
is_subscribe,
|
||||||
total_projects,
|
total_projects,
|
||||||
|
|||||||
@ -187,7 +187,7 @@ export function ChatConversationList({
|
|||||||
<div className="flex items-center gap-0.5">
|
<div className="flex items-center gap-0.5">
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsSearchOpen(!isSearchOpen)}
|
onClick={() => setIsSearchOpen(!isSearchOpen)}
|
||||||
className="flex size-8 items-center justify-center rounded-full transition-colors hover:bg-[var(--hover-bg)]"
|
className="flex size-8 items-center justify-center rounded-full"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{ color: "var(--text-muted)" }}
|
||||||
title={t("navigation.search_shortcut")}
|
title={t("navigation.search_shortcut")}
|
||||||
>
|
>
|
||||||
@ -196,7 +196,7 @@ export function ChatConversationList({
|
|||||||
<button
|
<button
|
||||||
onClick={handleNew}
|
onClick={handleNew}
|
||||||
disabled={createMutation.isPending}
|
disabled={createMutation.isPending}
|
||||||
className="flex size-8 items-center justify-center rounded-full transition-colors hover:bg-[var(--hover-bg)]"
|
className="flex size-8 items-center justify-center rounded-full"
|
||||||
style={{ color: "var(--text-secondary)" }}
|
style={{ color: "var(--text-secondary)" }}
|
||||||
title={t("chat.header.new_chat")}
|
title={t("chat.header.new_chat")}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -31,10 +31,6 @@ export function ChatHeader({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="sticky top-0 z-10 flex h-12 shrink-0 items-center justify-between border-b border-border/60 bg-background/85 px-4 backdrop-blur-xl supports-[backdrop-filter]:bg-background/70"
|
className="sticky top-0 z-10 flex h-12 shrink-0 items-center justify-between border-b border-border/60 bg-background/85 px-4 backdrop-blur-xl supports-[backdrop-filter]:bg-background/70"
|
||||||
style={{
|
|
||||||
boxShadow:
|
|
||||||
"0 1px 0 color-mix(in oklch, var(--border) 60%, transparent)",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="flex min-w-0 items-center gap-2.5">
|
<div className="flex min-w-0 items-center gap-2.5">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -209,7 +209,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="group mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-transparent px-4 py-4 transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-secondary)]/40">
|
<div className="group mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-transparent px-4 py-4">
|
||||||
{/* Avatar */}
|
{/* Avatar */}
|
||||||
<div className="shrink-0 pt-0.5">
|
<div className="shrink-0 pt-0.5">
|
||||||
{isUser ? (
|
{isUser ? (
|
||||||
@ -409,7 +409,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
{message.version_number > 1 && (
|
{message.version_number > 1 && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowVersions(!showVersions)}
|
onClick={() => setShowVersions(!showVersions)}
|
||||||
className="mt-2 inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-secondary)] px-2.5 py-1 text-[11px] text-muted-foreground transition-colors hover:border-[var(--border-default)] hover:bg-[var(--surface-elevated)]"
|
className="mt-2 inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-secondary)] px-2.5 py-1 text-[11px] text-muted-foreground"
|
||||||
>
|
>
|
||||||
<span className="font-medium text-[var(--text-primary)]">
|
<span className="font-medium text-[var(--text-primary)]">
|
||||||
v{message.version_number}
|
v{message.version_number}
|
||||||
@ -427,7 +427,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
<button
|
<button
|
||||||
key={v.id}
|
key={v.id}
|
||||||
onClick={() => handleSwitchVersion(v.version_number)}
|
onClick={() => handleSwitchVersion(v.version_number)}
|
||||||
className="flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left transition-colors hover:bg-[var(--hover-bg)]"
|
className="flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left"
|
||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
v.version_number === message.version_number
|
v.version_number === message.version_number
|
||||||
@ -467,7 +467,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
<div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
|
<div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
|
||||||
<button
|
<button
|
||||||
onClick={handleStartEdit}
|
onClick={handleStartEdit}
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]"
|
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{ color: "var(--text-muted)" }}
|
||||||
>
|
>
|
||||||
<Pencil className="size-3" />
|
<Pencil className="size-3" />
|
||||||
@ -476,7 +476,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
{onRegenerate && (
|
{onRegenerate && (
|
||||||
<button
|
<button
|
||||||
onClick={handleRegenerate}
|
onClick={handleRegenerate}
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]"
|
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{ color: "var(--text-muted)" }}
|
||||||
>
|
>
|
||||||
<RefreshCw className="size-3" />
|
<RefreshCw className="size-3" />
|
||||||
@ -491,7 +491,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
<div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
|
<div className="mt-2 flex flex-wrap items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
|
||||||
<button
|
<button
|
||||||
onClick={handleCopyAnswer}
|
onClick={handleCopyAnswer}
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]"
|
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{ color: "var(--text-muted)" }}
|
||||||
>
|
>
|
||||||
{copied === "answer" ? (
|
{copied === "answer" ? (
|
||||||
@ -504,7 +504,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
{hasThinking && (
|
{hasThinking && (
|
||||||
<button
|
<button
|
||||||
onClick={handleCopyFull}
|
onClick={handleCopyFull}
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]"
|
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{ color: "var(--text-muted)" }}
|
||||||
>
|
>
|
||||||
{copied === "full" ? (
|
{copied === "full" ? (
|
||||||
@ -517,7 +517,7 @@ export const ChatMessageBubble = memo(function ChatMessageBubble({
|
|||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={handleFork}
|
onClick={handleFork}
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-transparent px-2.5 py-1 text-[11px] transition-colors hover:border-[var(--border-subtle)] hover:bg-[var(--surface-elevated)]"
|
className="inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[11px]"
|
||||||
style={{ color: "var(--text-muted)" }}
|
style={{ color: "var(--text-muted)" }}
|
||||||
>
|
>
|
||||||
<GitFork className="size-3" />
|
<GitFork className="size-3" />
|
||||||
|
|||||||
@ -346,7 +346,7 @@ export function ChatMessageInput({
|
|||||||
|
|
||||||
{showModelWarning && (
|
{showModelWarning && (
|
||||||
<div
|
<div
|
||||||
className="absolute -top-11 right-0 left-0 flex animate-bounce items-center justify-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium shadow-sm"
|
className="absolute -top-11 right-0 left-0 flex animate-bounce items-center justify-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--accent-muted)",
|
backgroundColor: "var(--accent-muted)",
|
||||||
color: "var(--accent)",
|
color: "var(--accent)",
|
||||||
@ -359,7 +359,7 @@ export function ChatMessageInput({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Card className="overflow-hidden border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/80 shadow-lg backdrop-blur">
|
<Card className="overflow-hidden border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/80 backdrop-blur">
|
||||||
<PromptInput onSubmit={handleSubmit}>
|
<PromptInput onSubmit={handleSubmit}>
|
||||||
<PromptInputBody>
|
<PromptInputBody>
|
||||||
{selectedContexts.length > 0 && (
|
{selectedContexts.length > 0 && (
|
||||||
@ -381,7 +381,7 @@ export function ChatMessageInput({
|
|||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="inline-flex items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100"
|
className="inline-flex items-center justify-center rounded-full opacity-70 transition-opacity"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setSelectedContexts((current) =>
|
setSelectedContexts((current) =>
|
||||||
current.filter(
|
current.filter(
|
||||||
|
|||||||
@ -178,7 +178,7 @@ export function ChatMessageList({
|
|||||||
{PROMPT_SUGGESTIONS.map((s, i) => (
|
{PROMPT_SUGGESTIONS.map((s, i) => (
|
||||||
<button
|
<button
|
||||||
key={i}
|
key={i}
|
||||||
className="flex items-start gap-2.5 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-ground)] p-4 text-left transition-all duration-200 hover:-translate-y-0.5 hover:border-[var(--border-default)] hover:bg-[var(--surface-elevated)] hover:shadow-sm"
|
className="flex items-start gap-2.5 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-ground)] p-4 text-left"
|
||||||
style={{
|
style={{
|
||||||
color: "var(--text-secondary)",
|
color: "var(--text-secondary)",
|
||||||
}}
|
}}
|
||||||
@ -217,7 +217,7 @@ export function ChatMessageList({
|
|||||||
>
|
>
|
||||||
{isStreaming && userScrolledUp && (
|
{isStreaming && userScrolledUp && (
|
||||||
<div
|
<div
|
||||||
className="absolute bottom-3 left-1/2 z-10 -translate-x-1/2 cursor-pointer rounded-full border px-4 py-1.5 shadow-lg transition-all hover:scale-105"
|
className="absolute bottom-3 left-1/2 z-10 -translate-x-1/2 cursor-pointer rounded-full border px-4 py-1.5"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--surface-elevated)",
|
backgroundColor: "var(--surface-elevated)",
|
||||||
borderColor: "var(--border-subtle)",
|
borderColor: "var(--border-subtle)",
|
||||||
@ -401,7 +401,7 @@ function StreamingBubble({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={contentRef}
|
ref={contentRef}
|
||||||
className="mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3 shadow-sm backdrop-blur"
|
className="mx-auto flex w-full max-w-3xl gap-4 rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3 backdrop-blur"
|
||||||
>
|
>
|
||||||
<div className="shrink-0 pt-0.5">
|
<div className="shrink-0 pt-0.5">
|
||||||
<StreamingModelAvatar modelName={selectedModel?.model_name} size={28} />
|
<StreamingModelAvatar modelName={selectedModel?.model_name} size={28} />
|
||||||
|
|||||||
@ -135,7 +135,7 @@ export function ChatModelSelector({
|
|||||||
return (
|
return (
|
||||||
<ModelSelector open={open} onOpenChange={setOpen}>
|
<ModelSelector open={open} onOpenChange={setOpen}>
|
||||||
<ModelSelectorTrigger asChild>
|
<ModelSelectorTrigger asChild>
|
||||||
<button className="inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-elevated)] px-3 py-1.5 text-xs font-medium text-[var(--text-primary)] shadow-sm transition-all hover:-translate-y-0.5 hover:border-[var(--border-default)] hover:bg-[var(--surface-secondary)]">
|
<button className="inline-flex items-center gap-2 rounded-full border border-[var(--border-subtle)] bg-[var(--surface-elevated)] px-3 py-1.5 text-xs font-medium text-[var(--text-primary)]">
|
||||||
{selectedModel ? (
|
{selectedModel ? (
|
||||||
<ModelAvatar modelName={selectedModel.model_name} size={18} />
|
<ModelAvatar modelName={selectedModel.model_name} size={18} />
|
||||||
) : (
|
) : (
|
||||||
@ -155,7 +155,7 @@ export function ChatModelSelector({
|
|||||||
|
|
||||||
<ModelSelectorContent
|
<ModelSelectorContent
|
||||||
title={t("chat.model_selector.search_placeholder")}
|
title={t("chat.model_selector.search_placeholder")}
|
||||||
className="w-[min(92vw,38rem)] overflow-hidden rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-elevated)] p-0 shadow-2xl"
|
className="w-[min(92vw,38rem)] overflow-hidden rounded-2xl border border-[var(--border-subtle)] bg-[var(--surface-elevated)] p-0"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between gap-3 border-b border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3">
|
<div className="flex items-center justify-between gap-3 border-b border-[var(--border-subtle)] bg-[var(--surface-secondary)]/70 px-4 py-3">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export function ChatSlashCommandMenu({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="absolute inset-x-0 bottom-full z-20 mb-2 overflow-hidden rounded-2xl border shadow-2xl"
|
className="absolute inset-x-0 bottom-full z-20 mb-2 overflow-hidden rounded-2xl border"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "var(--surface-elevated)",
|
backgroundColor: "var(--surface-elevated)",
|
||||||
borderColor: "var(--border-subtle)",
|
borderColor: "var(--border-subtle)",
|
||||||
@ -76,7 +76,7 @@ export function ChatSlashCommandMenu({
|
|||||||
type="button"
|
type="button"
|
||||||
onMouseEnter={() => onHoverIndex(index)}
|
onMouseEnter={() => onHoverIndex(index)}
|
||||||
onClick={() => onPickItem(item)}
|
onClick={() => onPickItem(item)}
|
||||||
className="flex w-full items-start justify-between gap-3 rounded-xl px-3 py-2 text-left transition-colors"
|
className="flex w-full items-start justify-between gap-3 rounded-xl px-3 py-2 text-left"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
activeIndex === index ? "var(--hover-bg)" : "transparent",
|
activeIndex === index ? "var(--hover-bg)" : "transparent",
|
||||||
|
|||||||
@ -157,7 +157,7 @@ export function ProfileHeader({
|
|||||||
<Calendar className="size-3.5" />
|
<Calendar className="size-3.5" />
|
||||||
<span>
|
<span>
|
||||||
{t("me.profile.joined")}{" "}
|
{t("me.profile.joined")}{" "}
|
||||||
{format(new Date(user.created_at), "MMM yyyy")}
|
{user.created_at ? format(new Date(user.created_at), "MMM yyyy") : null}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{user.organization && (
|
{user.organization && (
|
||||||
|
|||||||
@ -85,15 +85,6 @@ export function MessageInput({
|
|||||||
color: 'var(--text-muted)',
|
color: 'var(--text-muted)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
transition: 'all 0.15s',
|
|
||||||
}}
|
|
||||||
onMouseEnter={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'var(--hover-bg)';
|
|
||||||
e.currentTarget.style.color = 'var(--text-primary)';
|
|
||||||
}}
|
|
||||||
onMouseLeave={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'transparent';
|
|
||||||
e.currentTarget.style.color = 'var(--text-muted)';
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<X className="w-3.5 h-3.5" />
|
<X className="w-3.5 h-3.5" />
|
||||||
@ -137,19 +128,8 @@ export function MessageInput({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
transition: 'all 0.15s',
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
|
||||||
if (!uploading) {
|
|
||||||
e.currentTarget.style.backgroundColor = 'var(--hover-bg)';
|
|
||||||
e.currentTarget.style.color = 'var(--accent)';
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onMouseLeave={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'transparent';
|
|
||||||
e.currentTarget.style.color = 'var(--text-muted)';
|
|
||||||
}}
|
|
||||||
title="Attach file"
|
title="Attach file"
|
||||||
>
|
>
|
||||||
{uploading ? (
|
{uploading ? (
|
||||||
@ -201,17 +181,8 @@ export function MessageInput({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
transition: 'all 0.15s',
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'var(--hover-bg)';
|
|
||||||
e.currentTarget.style.color = 'var(--accent)';
|
|
||||||
}}
|
|
||||||
onMouseLeave={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'transparent';
|
|
||||||
e.currentTarget.style.color = 'var(--text-muted)';
|
|
||||||
}}
|
|
||||||
title="Add emoji"
|
title="Add emoji"
|
||||||
>
|
>
|
||||||
<Smile className="w-5 h-5" />
|
<Smile className="w-5 h-5" />
|
||||||
@ -230,17 +201,8 @@ export function MessageInput({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
transition: 'all 0.15s',
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'var(--hover-bg)';
|
|
||||||
e.currentTarget.style.color = 'var(--accent)';
|
|
||||||
}}
|
|
||||||
onMouseLeave={(e) => {
|
|
||||||
e.currentTarget.style.backgroundColor = 'transparent';
|
|
||||||
e.currentTarget.style.color = 'var(--text-muted)';
|
|
||||||
}}
|
|
||||||
title="Mention someone"
|
title="Mention someone"
|
||||||
>
|
>
|
||||||
<AtSign className="w-5 h-5" />
|
<AtSign className="w-5 h-5" />
|
||||||
|
|||||||
@ -12,7 +12,7 @@ function Card({
|
|||||||
data-slot="card"
|
data-slot="card"
|
||||||
data-size={size}
|
data-size={size}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
data-slot="input-group"
|
data-slot="input-group"
|
||||||
role="group"
|
role="group"
|
||||||
className={cn(
|
className={cn(
|
||||||
"group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
|
"group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg outline-none has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@ -35,11 +35,6 @@ export default defineConfig({
|
|||||||
watch: {
|
watch: {
|
||||||
ignored: ["**/libs/**", "**/target/**"],
|
ignored: ["**/libs/**", "**/target/**"],
|
||||||
},
|
},
|
||||||
hmr: {
|
|
||||||
host: "localhost",
|
|
||||||
port: 5080,
|
|
||||||
protocol: "ws",
|
|
||||||
},
|
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api": {
|
"/api": {
|
||||||
target: "http://localhost:8080",
|
target: "http://localhost:8080",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user