mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 19:47:43 +01:00
style: search data display (#380)
* style: search date display * style: adjust style * style: search detail display * docs: update notes * build: build error
This commit is contained in:
@@ -29,14 +29,13 @@ Information about release notes of Coco Server is provided here.
|
|||||||
- fix: active shadow setting #354
|
- fix: active shadow setting #354
|
||||||
- fix: chat history was not show up #377
|
- fix: chat history was not show up #377
|
||||||
|
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
- refactor: web components #331
|
- refactor: web components #331
|
||||||
- refactor: refactoring login callback, receive access_token from coco-server
|
- refactor: refactoring login callback, receive access_token from coco-server
|
||||||
- chore: adjust web component styles #362
|
- chore: adjust web component styles #362
|
||||||
- style: modify the style #370
|
- style: modify the style #370
|
||||||
- style: search list details display #378
|
- style: search list details display #378 #380
|
||||||
|
|
||||||
## 0.3.0 (2025-03-31)
|
## 0.3.0 (2025-03-31)
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function ChatHeader({
|
|||||||
reconnect,
|
reconnect,
|
||||||
setIsLogin,
|
setIsLogin,
|
||||||
isChatPage = false,
|
isChatPage = false,
|
||||||
showChatHistory,
|
showChatHistory = true,
|
||||||
}: ChatHeaderProps) {
|
}: ChatHeaderProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -199,20 +199,20 @@ export function ChatHeader({
|
|||||||
data-tauri-drag-region
|
data-tauri-drag-region
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{isTauri && (
|
{showChatHistory && (
|
||||||
<button
|
<button
|
||||||
data-sidebar-button
|
data-sidebar-button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsSidebarOpen();
|
setIsSidebarOpen();
|
||||||
}}
|
}}
|
||||||
className="py-1 px-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800"
|
className="p-2 py-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||||
>
|
>
|
||||||
<VisibleKey
|
<VisibleKey
|
||||||
shortcut={historicalRecords}
|
shortcut={historicalRecords}
|
||||||
onKeypress={setIsSidebarOpen}
|
onKeypress={setIsSidebarOpen}
|
||||||
>
|
>
|
||||||
<HistoryIcon />
|
<HistoryIcon className="h-4 w-4" />
|
||||||
</VisibleKey>
|
</VisibleKey>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@@ -250,13 +250,13 @@ export function ChatHeader({
|
|||||||
) : null}
|
) : null}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
{showChatHistory && isTauri ? (
|
{showChatHistory ? (
|
||||||
<button
|
<button
|
||||||
onClick={onCreateNewChat}
|
onClick={onCreateNewChat}
|
||||||
className="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800"
|
className="p-2 py-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||||
>
|
>
|
||||||
<VisibleKey shortcut={newSession} onKeypress={onCreateNewChat}>
|
<VisibleKey shortcut={newSession} onKeypress={onCreateNewChat}>
|
||||||
<MessageSquarePlus className="h-4 w-4" />
|
<MessageSquarePlus className="h-4 w-4 relative top-0.5" />
|
||||||
</VisibleKey>
|
</VisibleKey>
|
||||||
</button>
|
</button>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { OpenURLWithBrowser } from "@/utils/index";
|
import { OpenURLWithBrowser } from "@/utils/index";
|
||||||
import type { IChunkData } from "@/components/Assistant/types";
|
import type { IChunkData } from "@/components/Assistant/types";
|
||||||
import RetrieveIcon from "@/icons/Retrieve";
|
import RetrieveIcon from "@/icons/Retrieve";
|
||||||
import { useAppStore } from "@/stores/appStore";
|
|
||||||
|
|
||||||
interface FetchSourceProps {
|
interface FetchSourceProps {
|
||||||
Detail?: any;
|
Detail?: any;
|
||||||
@@ -41,7 +40,6 @@ export const FetchSource = ({
|
|||||||
loading,
|
loading,
|
||||||
}: FetchSourceProps) => {
|
}: FetchSourceProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isTauri = useAppStore((state) => state.isTauri);
|
|
||||||
|
|
||||||
const [isSourceExpanded, setIsSourceExpanded] = useState(false);
|
const [isSourceExpanded, setIsSourceExpanded] = useState(false);
|
||||||
|
|
||||||
@@ -138,9 +136,7 @@ export const FetchSource = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`flex mobile:hidden w-[25%] items-center justify-end gap-2`}
|
||||||
isTauri ? "flex" : "hidden md:flex"
|
|
||||||
} w-[25%] items-center justify-end gap-2`}
|
|
||||||
>
|
>
|
||||||
<span className="text-xs text-[#999999] dark:text-[#999999] truncate">
|
<span className="text-xs text-[#999999] dark:text-[#999999] truncate">
|
||||||
{item.source?.name}
|
{item.source?.name}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export default function Footer({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`${isTauri ? "flex" : "hidden md:flex"} items-center gap-3`}
|
className={`flex mobile:hidden items-center gap-3`}
|
||||||
>
|
>
|
||||||
<div className="gap-1 flex items-center text-[#666] dark:text-[#666] text-xs">
|
<div className="gap-1 flex items-center text-[#666] dark:text-[#666] text-xs">
|
||||||
<span className="mr-1.5">{t("search.footer.select")}:</span>
|
<span className="mr-1.5">{t("search.footer.select")}:</span>
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { isMac } from "@/utils/platform";
|
import { isMac } from "@/utils/platform";
|
||||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||||
import noDataImg from "@/assets/coconut-tree.png";
|
import noDataImg from "@/assets/coconut-tree.png";
|
||||||
import { useAppStore } from "@/stores/appStore";
|
|
||||||
|
|
||||||
export const NoResults = () => {
|
export const NoResults = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isTauri = useAppStore((state) => state.isTauri);
|
|
||||||
const modeSwitch = useShortcutsStore((state) => state.modeSwitch);
|
const modeSwitch = useShortcutsStore((state) => state.modeSwitch);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -21,7 +19,7 @@ export const NoResults = () => {
|
|||||||
<div className="mt-4 text-sm text-[#999] dark:text-[#666]">
|
<div className="mt-4 text-sm text-[#999] dark:text-[#666]">
|
||||||
{t("search.main.noResults")}
|
{t("search.main.noResults")}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${isTauri ? 'flex' : 'hidden md:flex'} mt-10 text-sm text-[#333] dark:text-[#D8D8D8]`}>
|
<div className={`flex mobile:hidden mt-10 text-sm text-[#333] dark:text-[#D8D8D8]`}>
|
||||||
{t("search.main.askCoco")}
|
{t("search.main.askCoco")}
|
||||||
{isMac ? (
|
{isMac ? (
|
||||||
<span className="ml-3 w-5 h-5 rounded-[6px] border border-[#D8D8D8] flex justify-center items-center">
|
<span className="ml-3 w-5 h-5 rounded-[6px] border border-[#D8D8D8] flex justify-center items-center">
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { POPOVER_PANEL_SELECTOR } from "@/constants";
|
import { FC, ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
|
||||||
import { useKeyPress } from "ahooks";
|
import { useKeyPress } from "ahooks";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { FC, ReactNode, useEffect, useRef, useState } from "react";
|
|
||||||
|
import { POPOVER_PANEL_SELECTOR } from "@/constants";
|
||||||
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||||
|
|
||||||
interface VisibleKeyProps {
|
interface VisibleKeyProps {
|
||||||
shortcut: string;
|
shortcut: string;
|
||||||
@@ -64,17 +65,23 @@ const VisibleKey: FC<VisibleKeyProps> = (props) => {
|
|||||||
return shortcut;
|
return shortcut;
|
||||||
};
|
};
|
||||||
|
|
||||||
return visibleShortcut ? (
|
return (
|
||||||
|
<div
|
||||||
|
ref={childrenRef}
|
||||||
|
className={clsx("relative inline-block")}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{visibleShortcut ? (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"size-4 flex items-center justify-center font-normal text-xs text-[#333] leading-[14px] bg-[#ccc] dark:bg-[#6B6B6B] rounded-md shadow-[-6px_0px_6px_2px_#fff] dark:shadow-[-6px_0px_6px_2px_#000]",
|
"size-4 flex items-center justify-center font-normal text-xs text-[#333] leading-[14px] bg-[#ccc] dark:bg-[#6B6B6B] rounded-md shadow-[-6px_0px_6px_2px_#fff] dark:shadow-[-6px_0px_6px_2px_#000] absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{renderShortcut()}
|
{renderShortcut()}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : null}
|
||||||
<div ref={childrenRef}>{children}</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
import { formatter } from "@/utils/index";
|
import { formatter } from "@/utils/index";
|
||||||
import TypeIcon from "@/components/Common/Icons/TypeIcon";
|
import TypeIcon from "@/components/Common/Icons/TypeIcon";
|
||||||
|
import defaultThumbnail from "@/assets/coconut-tree.png";
|
||||||
|
import ItemIcon from "@/components/Common/Icons/ItemIcon";
|
||||||
|
|
||||||
interface DocumentDetailProps {
|
interface DocumentDetailProps {
|
||||||
document: any;
|
document: any;
|
||||||
@@ -16,9 +18,9 @@ interface DetailItemProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DetailItem: React.FC<DetailItemProps> = ({ label, value, icon }) => (
|
const DetailItem: React.FC<DetailItemProps> = ({ label, value, icon }) => (
|
||||||
<div className="flex justify-between flex-wrap font-normal text-xs mb-2.5">
|
<div className="flex justify-between flex-wrap font-normal text-xs mb-2.5 border-t border-[rgba(238,240,243,1)] dark:border-[#272626] pt-2.5">
|
||||||
<div className="text-[#666]">{label}</div>
|
<div className="text-[rgba(153,153,153,1)] dark:text-[#666]">{label}</div>
|
||||||
<div className="text-[#333] dark:text-[#D8D8D8] flex justify-end text-right w-56 break-words">
|
<div className="text-[rgba(51,51,51,1);] dark:text-[#D8D8D8] flex justify-end text-right w-56 break-words">
|
||||||
{icon}
|
{icon}
|
||||||
{value}
|
{value}
|
||||||
</div>
|
</div>
|
||||||
@@ -30,17 +32,52 @@ export const DocumentDetail: React.FC<DocumentDetailProps> = ({ document }) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-3">
|
||||||
<div className="font-normal text-xs text-[#666] dark:text-[#999] mb-2">
|
{/* <div className="font-normal text-xs text-[#666] dark:text-[#999] mb-2">
|
||||||
{t("search.document.details")}
|
{t("search.document.details")}
|
||||||
|
</div> */}
|
||||||
|
<div className="text-xs font-normal text-[rgba(51,51,51,1)] dark:text-[#D8D8D8]">
|
||||||
|
{document?.title || "-"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-4 mt-4">
|
<div className="py-4">
|
||||||
{/* Basic Information */}
|
{/* Document Thumbnail */}
|
||||||
<DetailItem
|
<div className="mb-4 h-[140px] rounded-lg bg-[rgba(243,244,246,1)] dark:bg-[#202126] flex justify-center items-center">
|
||||||
label={t("search.document.name")}
|
{document.thumbnail ? (
|
||||||
value={document?.title || "-"}
|
<img
|
||||||
|
src={document.thumbnail}
|
||||||
|
alt="thumbnail"
|
||||||
|
className="max-w-[200px] max-h-[120px] object-contain"
|
||||||
|
onError={(e) => {
|
||||||
|
const target = e.target as HTMLImageElement;
|
||||||
|
target.src = defaultThumbnail;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<ItemIcon item={document} className="w-16 h-16"/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Document Summary */}
|
||||||
|
{document?.summary && (
|
||||||
|
<div className="mb-4 text-xs text-[rgba(153,153,153,1)] dark:text-[#D8D8D8] whitespace-pre-wrap break-words">
|
||||||
|
{document.summary}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Document Tags */}
|
||||||
|
{document?.tags && document.tags.length > 0 && (
|
||||||
|
<div className="mb-4 flex flex-wrap gap-1">
|
||||||
|
{document.tags.map((tag: string, index: number) => (
|
||||||
|
<span
|
||||||
|
key={index}
|
||||||
|
className="px-2 py-0.5 text-xs rounded-full bg-blue-50 text-blue-600 dark:bg-blue-900/30 dark:text-blue-300"
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={t("search.document.source")}
|
label={t("search.document.source")}
|
||||||
@@ -66,20 +103,6 @@ export const DocumentDetail: React.FC<DocumentDetailProps> = ({ document }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Document Thumbnail */}
|
|
||||||
{document?.thumbnail && (
|
|
||||||
<DetailItem
|
|
||||||
label={t("search.document.thumbnail")}
|
|
||||||
value={
|
|
||||||
<img
|
|
||||||
src={document.thumbnail}
|
|
||||||
alt="thumbnail"
|
|
||||||
className="max-w-[200px] max-h-[120px] object-contain"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Document Identifier */}
|
{/* Document Identifier */}
|
||||||
{document?.id && (
|
{document?.id && (
|
||||||
<DetailItem label={t("search.document.id")} value={document.id} />
|
<DetailItem label={t("search.document.id")} value={document.id} />
|
||||||
@@ -117,30 +140,6 @@ export const DocumentDetail: React.FC<DocumentDetailProps> = ({ document }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Document Tags */}
|
|
||||||
{document?.tags && document.tags.length > 0 && (
|
|
||||||
<DetailItem
|
|
||||||
label={t("search.document.tags")}
|
|
||||||
value={
|
|
||||||
<div className="text-right whitespace-pre-wrap break-words w-full">
|
|
||||||
{document.tags.join(", ")}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Document Summary */}
|
|
||||||
{document?.summary && (
|
|
||||||
<DetailItem
|
|
||||||
label={t("search.document.summary")}
|
|
||||||
value={
|
|
||||||
<div className="text-right whitespace-pre-wrap break-words w-full">
|
|
||||||
{document.summary}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Last Update Time */}
|
{/* Last Update Time */}
|
||||||
{document?.updated && (
|
{document?.updated && (
|
||||||
<DetailItem
|
<DetailItem
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import TypeIcon from "@/components/Common/Icons/TypeIcon";
|
|||||||
import SearchListItem from "./SearchListItem";
|
import SearchListItem from "./SearchListItem";
|
||||||
import { metaOrCtrlKey, isMetaOrCtrlKey } from "@/utils/keyboardUtils";
|
import { metaOrCtrlKey, isMetaOrCtrlKey } from "@/utils/keyboardUtils";
|
||||||
import { OpenURLWithBrowser } from "@/utils/index";
|
import { OpenURLWithBrowser } from "@/utils/index";
|
||||||
|
import VisibleKey from "@/components/Common/VisibleKey";
|
||||||
|
|
||||||
type ISearchData = Record<string, any[]>;
|
type ISearchData = Record<string, any[]>;
|
||||||
|
|
||||||
@@ -190,7 +191,10 @@ function DropdownList({
|
|||||||
<ThemedIcon component={ArrowBigRight} className="w-4 h-4" />
|
<ThemedIcon component={ArrowBigRight} className="w-4 h-4" />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
{showIndex && sourceName === selectedName ? (
|
{showIndex && sourceName === selectedName ? (
|
||||||
<div className={`bg-[#ccc] dark:bg-[#6B6B6B] `}>→</div>
|
<div className="absolute top-0 right-4">
|
||||||
|
<VisibleKey shortcut="→" />
|
||||||
|
</div>
|
||||||
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { DataSource } from "@/types/commands";
|
|||||||
// import { useConnectStore } from "@/stores/connectStore";
|
// import { useConnectStore } from "@/stores/connectStore";
|
||||||
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
import { useShortcutsStore } from "@/stores/shortcutsStore";
|
||||||
import Copyright from "@/components/Common/Copyright";
|
import Copyright from "@/components/Common/Copyright";
|
||||||
import VisibleKey from "../Common/VisibleKey";
|
import VisibleKey from "@/components/Common/VisibleKey";
|
||||||
|
|
||||||
interface ChatInputProps {
|
interface ChatInputProps {
|
||||||
onSend: (message: string) => void;
|
onSend: (message: string) => void;
|
||||||
@@ -335,15 +335,18 @@ export default function ChatInput({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showTooltip && !isChatMode && sourceData && (
|
{showTooltip && !isChatMode && sourceData && (
|
||||||
<VisibleKey shortcut="←" className="absolute left-0" />
|
<div className="absolute -top-[5px] left-2">
|
||||||
|
<VisibleKey shortcut="←" />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{showTooltip && (
|
{showTooltip && (
|
||||||
<VisibleKey
|
<div
|
||||||
shortcut={returnToInput}
|
className={clsx("absolute -top-[5px] left-2", {
|
||||||
className={clsx("absolute", {
|
"left-8": !isChatMode && sourceData,
|
||||||
"left-7": !isChatMode && sourceData,
|
|
||||||
})}
|
})}
|
||||||
/>
|
>
|
||||||
|
<VisibleKey shortcut={returnToInput} />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -390,7 +393,9 @@ export default function ChatInput({
|
|||||||
) : null} */}
|
) : null} */}
|
||||||
|
|
||||||
{showTooltip && isChatMode && (
|
{showTooltip && isChatMode && (
|
||||||
<VisibleKey shortcut="↩︎" className="absolute right-3" />
|
<div className="absolute top-[2px] right-[18px]">
|
||||||
|
<VisibleKey shortcut="↩︎" />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!connected && isChatMode ? (
|
{!connected && isChatMode ? (
|
||||||
@@ -441,11 +446,7 @@ export default function ChatInput({
|
|||||||
)}
|
)}
|
||||||
onClick={DeepThinkClick}
|
onClick={DeepThinkClick}
|
||||||
>
|
>
|
||||||
<VisibleKey
|
<VisibleKey shortcut={deepThinking} onKeypress={DeepThinkClick}>
|
||||||
shortcut={deepThinking}
|
|
||||||
onKeypress={DeepThinkClick}
|
|
||||||
className="!size-3"
|
|
||||||
>
|
|
||||||
<Brain
|
<Brain
|
||||||
className={`size-3 ${
|
className={`size-3 ${
|
||||||
isDeepThinkActive
|
isDeepThinkActive
|
||||||
@@ -474,7 +475,7 @@ export default function ChatInput({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!hasFeature.includes("search") && !hasFeature.includes("think") ? (
|
{!hasFeature.includes("search") && !hasFeature.includes("think") ? (
|
||||||
<div className="px-2">
|
<div className="px-[9px]">
|
||||||
<Copyright />
|
<Copyright />
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -489,10 +490,9 @@ export default function ChatInput({
|
|||||||
{isChatPage || hasModules?.length !== 2 ? null : (
|
{isChatPage || hasModules?.length !== 2 ? null : (
|
||||||
<div className="relative w-16 flex justify-end items-center">
|
<div className="relative w-16 flex justify-end items-center">
|
||||||
{showTooltip && (
|
{showTooltip && (
|
||||||
<VisibleKey
|
<div className="absolute right-[52px] -top-2 z-10">
|
||||||
shortcut={modeSwitch}
|
<VisibleKey shortcut={modeSwitch} />
|
||||||
className="absolute left-1 z-10"
|
</div>
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ChatSwitch
|
<ChatSwitch
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import TypeIcon from "@/components/Common/Icons/TypeIcon";
|
import TypeIcon from "@/components/Common/Icons/TypeIcon";
|
||||||
import RichIcon from "@/components/Common/Icons/RichIcon";
|
import RichIcon from "@/components/Common/Icons/RichIcon";
|
||||||
import { useAppStore } from "@/stores/appStore";
|
|
||||||
|
|
||||||
interface ListRightProps {
|
interface ListRightProps {
|
||||||
item: any;
|
item: any;
|
||||||
@@ -17,21 +16,14 @@ export default function ListRight({
|
|||||||
currentIndex,
|
currentIndex,
|
||||||
goToTwoPage,
|
goToTwoPage,
|
||||||
}: ListRightProps) {
|
}: ListRightProps) {
|
||||||
const isTauri = useAppStore((state) => state.isTauri);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex flex-1 ${
|
className={`flex flex-1 text-right min-w-[160px] pl-5 justify-end w-full h-full text-[12px] gap-2 items-center relative`}
|
||||||
isTauri
|
|
||||||
? "text-right min-w-[160px] pl-5 justify-end"
|
|
||||||
: "md:text-right text-left md:min-w-[160px] md:pl-5 md:justify-end justify-start"
|
|
||||||
} w-full h-full text-[12px] gap-2 items-center relative`}
|
|
||||||
>
|
>
|
||||||
{item?.rich_categories ? null : (
|
{item?.rich_categories ? null : (
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`w-4 h-4 cursor-pointer`}
|
||||||
isTauri ? "inline-block" : "hidden md:inline-block"
|
|
||||||
} w-4 h-4 cursor-pointer`}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
goToTwoPage && goToTwoPage(item);
|
goToTwoPage && goToTwoPage(item);
|
||||||
@@ -52,9 +44,7 @@ export default function ListRight({
|
|||||||
<div className="flex items-center justify-end max-w-[calc(100%-20px)] whitespace-nowrap">
|
<div className="flex items-center justify-end max-w-[calc(100%-20px)] whitespace-nowrap">
|
||||||
<RichIcon
|
<RichIcon
|
||||||
item={item}
|
item={item}
|
||||||
className={`${
|
className={`w-4 h-4 mr-2 cursor-pointer`}
|
||||||
isTauri ? "inline-block" : "hidden md:inline-block"
|
|
||||||
} w-4 h-4 mr-2 cursor-pointer`}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
goToTwoPage && goToTwoPage(item);
|
goToTwoPage && goToTwoPage(item);
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import React from "react";
|
|||||||
import { AlignLeft, Columns2 } from "lucide-react";
|
import { AlignLeft, Columns2 } from "lucide-react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { useAppStore } from "@/stores/appStore";
|
|
||||||
|
|
||||||
interface SearchHeaderProps {
|
interface SearchHeaderProps {
|
||||||
total: number;
|
total: number;
|
||||||
viewMode: "detail" | "list";
|
viewMode: "detail" | "list";
|
||||||
@@ -17,8 +15,6 @@ export const SearchHeader: React.FC<SearchHeaderProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isTauri = useAppStore((state) => state.isTauri);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between py-1">
|
<div className="flex items-center justify-between py-1">
|
||||||
<div className="text-xs text-gray-600 dark:text-gray-400">
|
<div className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
@@ -28,7 +24,7 @@ export const SearchHeader: React.FC<SearchHeaderProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
{t('search.header.results')}
|
{t('search.header.results')}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${isTauri ? 'flex' : 'hidden md:flex'} gap-2`}>
|
<div className={`flex mobile:hidden gap-2`}>
|
||||||
<div className="flex bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5">
|
<div className="flex bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5">
|
||||||
<button
|
<button
|
||||||
onClick={() => setViewMode("list")}
|
onClick={() => setViewMode("list")}
|
||||||
|
|||||||
@@ -49,22 +49,18 @@ const SearchListItem: React.FC<SearchListItemProps> = React.memo(
|
|||||||
ref={itemRef}
|
ref={itemRef}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onClick={onItemClick}
|
onClick={onItemClick}
|
||||||
className={`w-full px-2 py-2.5 text-sm flex ${
|
className={`w-full px-2 py-2.5 text-sm flex mb-0 flex-row items-center mobile:mb-2 mobile:flex-col mobile:items-start justify-between rounded-lg transition-colors cursor-pointer ${
|
||||||
isTauri
|
|
||||||
? "mb-0 flex-row items-center"
|
|
||||||
: "md:mb-0 mb-2 md:flex-row flex-col md:items-center items-start"
|
|
||||||
} justify-between rounded-lg transition-colors cursor-pointer ${
|
|
||||||
isSelected
|
isSelected
|
||||||
? "text-white bg-[var(--coco-primary-color)] hover:bg-[var(--coco-primary-color)]"
|
? "text-white bg-[var(--coco-primary-color)] hover:bg-[var(--coco-primary-color)]"
|
||||||
: isTauri
|
: "text-[#333] dark:text-[#d8d8d8] mobile:bg-gray-200/80 mobile:dark:bg-gray-700/50"
|
||||||
? "text-[#333] dark:text-[#d8d8d8]"
|
} ${showListRight ? "gap-7 mobile:gap-1" : ""}`}
|
||||||
: "text-[#333] dark:text-[#d8d8d8] md:bg-transparent md:dark:bg-transparent bg-gray-200/80 dark:bg-gray-700/50"
|
|
||||||
} ${showListRight ? (isTauri ? "gap-7" : "md:gap-7 gap-1") : ""}`}
|
|
||||||
onContextMenu={onContextMenu}
|
onContextMenu={onContextMenu}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
showListRight ? "md:max-w-[450px] w-full" : "flex-1"
|
showListRight
|
||||||
|
? "max-w-[450px] mobile:w-full"
|
||||||
|
: "flex-1"
|
||||||
} min-w-0 flex gap-2 items-center justify-start `}
|
} min-w-0 flex gap-2 items-center justify-start `}
|
||||||
>
|
>
|
||||||
<ItemIcon item={item} />
|
<ItemIcon item={item} />
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ export default function SearchPopover({
|
|||||||
)}
|
)}
|
||||||
onClick={setIsSearchActive}
|
onClick={setIsSearchActive}
|
||||||
>
|
>
|
||||||
<VisibleKey shortcut={internetSearch} onKeypress={setIsSearchActive} className="!size-3">
|
<VisibleKey shortcut={internetSearch} onKeypress={setIsSearchActive}>
|
||||||
<Globe
|
<Globe
|
||||||
className={`size-3 ${
|
className={`size-3 ${
|
||||||
isSearchActive
|
isSearchActive
|
||||||
@@ -229,7 +229,6 @@ export default function SearchPopover({
|
|||||||
onKeypress={() => {
|
onKeypress={() => {
|
||||||
buttonRef.current?.click();
|
buttonRef.current?.click();
|
||||||
}}
|
}}
|
||||||
className="!size-3"
|
|
||||||
>
|
>
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon
|
||||||
className={clsx("size-3", [
|
className={clsx("size-3", [
|
||||||
|
|||||||
@@ -291,8 +291,8 @@ function SearchChat({
|
|||||||
data-tauri-drag-region={isTauri}
|
data-tauri-drag-region={isTauri}
|
||||||
className={`p-2 absolute w-full flex justify-center transition-all duration-500 ${
|
className={`p-2 absolute w-full flex justify-center transition-all duration-500 ${
|
||||||
isTransitioned
|
isTransitioned
|
||||||
? "top-[calc(100%-84px)] h-[84px] border-t"
|
? "top-[calc(100%-82px)] h-[82px] border-t"
|
||||||
: "top-0 h-[84px] border-b"
|
: "top-0 h-[82px] border-b"
|
||||||
} border-[#E6E6E6] dark:border-[#272626]`}
|
} border-[#E6E6E6] dark:border-[#272626]`}
|
||||||
>
|
>
|
||||||
<InputBox
|
<InputBox
|
||||||
@@ -331,7 +331,7 @@ function SearchChat({
|
|||||||
data-tauri-drag-region={isTauri}
|
data-tauri-drag-region={isTauri}
|
||||||
className={`absolute w-full transition-opacity duration-500 ${
|
className={`absolute w-full transition-opacity duration-500 ${
|
||||||
isTransitioned ? "opacity-0 pointer-events-none" : "opacity-100"
|
isTransitioned ? "opacity-0 pointer-events-none" : "opacity-100"
|
||||||
} bottom-0 h-[calc(100%-84px)] `}
|
} bottom-0 h-[calc(100%-82px)] `}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<LoadingFallback />}>
|
<Suspense fallback={<LoadingFallback />}>
|
||||||
<Search
|
<Search
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
export const useIsMobile = (breakpoint: number = 768) => {
|
export const useIsMobile = (breakpoint: number = 679) => {
|
||||||
const [isMobile, setIsMobile] = useState(window.innerWidth <= breakpoint);
|
const [isMobile, setIsMobile] = useState(window.innerWidth <= breakpoint);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ function WebApp({
|
|||||||
hideCoco = () => {},
|
hideCoco = () => {},
|
||||||
hasModules = ["search", "chat"],
|
hasModules = ["search", "chat"],
|
||||||
defaultModule = "search",
|
defaultModule = "search",
|
||||||
hasFeature = ["search", "think", "think_active", "search_active"],
|
hasFeature = ["think_active", "search_active"],
|
||||||
theme = "dark",
|
theme = "dark",
|
||||||
searchPlaceholder = "",
|
searchPlaceholder = "",
|
||||||
chatPlaceholder = "",
|
chatPlaceholder = "",
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ export default {
|
|||||||
1000: "1000",
|
1000: "1000",
|
||||||
2000: "2000",
|
2000: "2000",
|
||||||
},
|
},
|
||||||
|
screens: {
|
||||||
|
'mobile': {'max': '679px'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
|
|||||||
Reference in New Issue
Block a user