Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/content.en/docs/release-notes/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ feat(View Extension): page field now accepts HTTP(s) links #925
feat: return sub-exts when extension type exts themselves are matched #928
feat: open quick ai with modifier key + enter #939
feat: allow navigate back when cursor is at the beginning #940
feat: add compact mode for window #947

### 🐛 Bug fix

Expand Down
1 change: 1 addition & 0 deletions src/components/Search/InputBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ export default function ChatInput({
<div className={`w-full relative`}>
<div
ref={containerRef}
id="search-bar"
className={`flex items-center dark:text-[#D8D8D8] rounded-md transition-all relative overflow-hidden`}
>
{lineCount === 1 && renderSearchIcon()}
Expand Down
1 change: 1 addition & 0 deletions src/components/Search/InputControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ const InputControls = ({

return (
<div
id="filter-bar"
data-tauri-drag-region
className="flex justify-between items-center pt-2"
>
Expand Down
56 changes: 50 additions & 6 deletions src/components/SearchChat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
useMemo,
} from "react";
import clsx from "clsx";
import { useMount } from "ahooks";
import { useMount, useMutationObserver } from "ahooks";

import Search from "@/components/Search/Search";
import InputBox from "@/components/Search/InputBox";
Expand All @@ -28,10 +28,12 @@ import { useConnectStore } from "@/stores/connectStore";
import { useAppearanceStore } from "@/stores/appearanceStore";
import type { StartPage } from "@/types/chat";
import {
canNavigateBack,
hasUploadingAttachment,
visibleFilterBar,
visibleSearchBar,
} from "@/utils";
import { useTauriFocus } from "@/hooks/useTauriFocus";

interface SearchChatProps {
isTauri?: boolean;
Expand Down Expand Up @@ -82,6 +84,7 @@ function SearchChat({
);

const [state, dispatch] = useReducer(appReducer, customInitialState);

const {
isChatMode,
input,
Expand All @@ -91,6 +94,52 @@ function SearchChat({
isMCPActive,
isTyping,
} = state;

const inputRef = useRef<string>();
const isChatModeRef = useRef(false);

const setWindowSize = useCallback(() => {
const width = 680;
let height = 590;

const updateAppDialog = document.querySelector("#update-app-dialog");

if (!updateAppDialog && !canNavigateBack() && !inputRef.current) {
const { windowMode } = useAppearanceStore.getState();

if (windowMode === "compact") {
const searchBar = document.querySelector("#search-bar");
const filterBar = document.querySelector("#filter-bar");

if (searchBar && filterBar) {
height = searchBar.clientHeight + filterBar.clientHeight + 16;
} else {
height = 82;
}

height = Math.min(height, 88);
}
}

platformAdapter.setWindowSize(width, height);
}, []);

useMutationObserver(setWindowSize, document.body, {
subtree: true,
childList: true,
});

useEffect(() => {
inputRef.current = input;
isChatModeRef.current = isChatMode;

setWindowSize();
}, [input, isChatMode]);

useTauriFocus({
onFocus: setWindowSize,
});

useEffect(() => {
dispatch({
type: "SET_SEARCH_ACTIVE",
Expand All @@ -114,11 +163,6 @@ function SearchChat({
const setTheme = useThemeStore((state) => state.setTheme);
const setIsDark = useThemeStore((state) => state.setIsDark);

const isChatModeRef = useRef(false);
useEffect(() => {
isChatModeRef.current = isChatMode;
}, [isChatMode]);

useMount(async () => {
const isWin10 = await platformAdapter.isWindows10();

Expand Down
10 changes: 0 additions & 10 deletions src/components/Settings/Advanced/components/Appearance/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import SettingsInput from "@/components/Settings/SettingsInput";
import SettingsItem from "@/components/Settings/SettingsItem";
import { useAppearanceStore } from "@/stores/appearanceStore";
import platformAdapter from "@/utils/platformAdapter";
import { AppWindowMac } from "lucide-react";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";

const Appearance = () => {
const { t } = useTranslation();
const opacity = useAppearanceStore((state) => state.opacity);
const setOpacity = useAppearanceStore((state) => state.setOpacity);

useEffect(() => {
const unlisten = useAppearanceStore.subscribe((state) => {
platformAdapter.emitEvent("change-appearance-store", state);
});

return unlisten;
}, []);

return (
<>
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
Expand Down
67 changes: 66 additions & 1 deletion src/components/Settings/GeneralSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import { useState, useEffect, cloneElement, ReactElement } from "react";
import {
Command,
Monitor,
Expand All @@ -9,6 +9,9 @@ import {
Tags,
// Trash2,
Globe,
PictureInPicture2,
PanelTop,
RectangleHorizontal,
} from "lucide-react";
import { useTranslation } from "react-i18next";
import { isTauri } from "@tauri-apps/api/core";
Expand All @@ -31,6 +34,8 @@ import {
unregister_shortcut,
} from "@/commands";
import platformAdapter from "@/utils/platformAdapter";
import clsx from "clsx";
import { useAppearanceStore, WindowMode } from "@/stores/appearanceStore";

export function ThemeOption({
icon: Icon,
Expand Down Expand Up @@ -76,6 +81,7 @@ export default function GeneralSettings() {
const [launchAtLogin, setLaunchAtLogin] = useState(true);

const { showTooltip, setShowTooltip, language, setLanguage } = useAppStore();
const { windowMode, setWindowMode } = useAppearanceStore();

const fetchAutoStartStatus = async () => {
if (isTauri()) {
Expand Down Expand Up @@ -176,6 +182,20 @@ export default function GeneralSettings() {

const currentLanguage = language || i18n.language;

const windowModes: Array<{
icon: ReactElement;
value: WindowMode;
}> = [
{
icon: <PanelTop />,
value: "default",
},
{
icon: <RectangleHorizontal />,
value: "compact",
},
];

return (
<div className="space-y-8">
<div>
Expand Down Expand Up @@ -239,6 +259,51 @@ export default function GeneralSettings() {
/>
</div>

<SettingsItem
icon={PictureInPicture2}
title={t("settings.windowMode.title")}
description={t("settings.windowMode.description")}
/>
<div className="grid grid-cols-3 gap-4">
{windowModes.map((item) => {
const { icon, value } = item;

const label = t(`settings.windowMode.${value}`);

let isSelected = value === windowMode;

return (
<button
onClick={() => {
setWindowMode(value);
}}
className={clsx(
"p-4 rounded-lg border-2 border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600 flex flex-col items-center justify-center space-y-2 transition-all",
{
"!border-blue-500 bg-blue-50 dark:bg-blue-900/20":
isSelected,
}
)}
title={label}
>
{cloneElement(icon, {
className: clsx({
"text-blue-500": isSelected,
}),
})}

<span
className={clsx(`text-sm font-medium`, {
"text-blue-500": isSelected,
})}
>
{label}
</span>
</button>
);
})}
</div>

<SettingsItem
icon={Globe}
title={t("settings.language.title")}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Settings/SettingsItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ interface SettingsItemProps {
icon: LucideIcon;
title: string;
description: string;
children: React.ReactNode;
children?: React.ReactNode;
}

export default function SettingsItem({
Expand Down
19 changes: 11 additions & 8 deletions src/components/UpdateApp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,8 @@ const UpdateApp = ({ isCheckPage }: UpdateAppProps) => {

const { skipVersions, updateInfo } = useUpdateStore.getState();

if(updateInfo?.version){
setSkipVersions([...skipVersions, updateInfo.version]);

if (updateInfo?.version) {
setSkipVersions([...skipVersions, updateInfo.version]);
}

isCheckPage ? hide_check() : setVisible(false);
Expand All @@ -143,6 +142,7 @@ const UpdateApp = ({ isCheckPage }: UpdateAppProps) => {
<Dialog
open={isCheckPage ? true : visible}
as="div"
id="update-app-dialog"
className="relative z-10 focus:outline-none"
onClose={noop}
>
Expand All @@ -154,18 +154,21 @@ const UpdateApp = ({ isCheckPage }: UpdateAppProps) => {
}`}
>
<div
data-tauri-drag-region
className={clsx(
"flex min-h-full items-center justify-center",
!isCheckPage && "p-4"
)}
>
<DialogPanel
transition
className={`relative w-[340px] py-8 flex flex-col items-center ${
isCheckPage
? ""
: "rounded-lg bg-white dark:bg-[#333] border border-[#EDEDED] dark:border-black/20 shadow-md"
}`}
className={clsx(
"relative w-[340px] py-8 flex flex-col items-center",
{
"rounded-lg bg-white dark:bg-[#333] border border-[#EDEDED] dark:border-black/20 shadow-md":
!isCheckPage,
}
)}
>
{!isCheckPage && isOptional && (
<X
Expand Down
17 changes: 9 additions & 8 deletions src/hooks/useSyncStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@ export const useSyncStore = () => {
const setShowTooltip = useAppStore((state) => state.setShowTooltip);
const setEndpoint = useAppStore((state) => state.setEndpoint);
const setLanguage = useAppStore((state) => state.setLanguage);

const setServerListSilently = useConnectStore((state) => state.setServerListSilently);
const { setWindowMode } = useAppearanceStore();

const setServerListSilently = useConnectStore(
(state) => state.setServerListSilently
);

useEffect(() => {
if (!resetFixedWindow) {
Expand Down Expand Up @@ -182,11 +185,8 @@ export const useSyncStore = () => {
}),

platformAdapter.listenEvent("change-connect-store", ({ payload }) => {
const {
connectionTimeout,
querySourceTimeout,
allowSelfSignature,
} = payload;
const { connectionTimeout, querySourceTimeout, allowSelfSignature } =
payload;
if (isNumber(connectionTimeout)) {
setConnectionTimeout(connectionTimeout);
}
Expand All @@ -197,12 +197,13 @@ export const useSyncStore = () => {
}),

platformAdapter.listenEvent("change-appearance-store", ({ payload }) => {
const { opacity, snapshotUpdate } = payload;
const { opacity, snapshotUpdate, windowMode } = payload;

if (isNumber(opacity)) {
setOpacity(opacity);
}
setSnapshotUpdate(snapshotUpdate);
setWindowMode(windowMode);
}),

platformAdapter.listenEvent("change-extensions-store", ({ payload }) => {
Expand Down
6 changes: 6 additions & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
"dark": "Dark",
"auto": "Auto"
},
"windowMode": {
"title": "Window Mode",
"description": "Set how the window appears when opened.",
"default": "Default",
"compact": "Compact"
},
"language": {
"title": "Language",
"description": "Choose your preferred language",
Expand Down
6 changes: 6 additions & 0 deletions src/locales/zh/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
"dark": "深色",
"auto": "自动"
},
"windowMode": {
"title": "窗口模式",
"description": "设置窗口打开时的显示方式。",
"default": "默认",
"compact": "紧凑"
},
"language": {
"title": "语言",
"description": "选择您的首选语言",
Expand Down
Loading