| author | |
| committer | |
| log | 41ebf22eea64e177b11a0709a16d6716581cc78c |
| tree | 7bce7f4433e41148fa1366c975ee9d05ec88696f |
| parent | 3d429662c9bd7b731c059dc3a84ccdfc43bf3701 |
| signature | Signed by PGP key B5690EEEBB952194 |
6 files changed, 30 insertions(+), 20 deletions(-)
apps/web/src/components/ChatMarkdown.tsx+4| ... | @@ -1363,6 +1363,9 @@ function ChatMarkdown({ | ... | @@ -1363,6 +1363,9 @@ function ChatMarkdown({ |
| 1363 | }, | 1363 | }, |
| 1364 | [createAssetUrl, openPreview, preparedConnection, threadRef], | 1364 | [createAssetUrl, openPreview, preparedConnection, threadRef], |
| 1365 | ); | 1365 | ); |
| 1366 | /* eslint-disable react/no-unstable-nested-components -- ReactMarkdown requires component | ||
| 1367 | * renderers that close over this message's metadata. useMemo keeps them stable until that | ||
| 1368 | * metadata changes. */ | ||
| 1366 | const markdownComponents = useMemo<Components>(() => { | 1369 | const markdownComponents = useMemo<Components>(() => { |
| 1367 | const fileLinkChip = ( | 1370 | const fileLinkChip = ( |
| 1368 | fileLinkMeta: MarkdownFileLinkMeta, | 1371 | fileLinkMeta: MarkdownFileLinkMeta, |
| ... | @@ -1593,6 +1596,7 @@ function ChatMarkdown({ | ... | @@ -1593,6 +1596,7 @@ function ChatMarkdown({ |
| 1593 | text, | 1596 | text, |
| 1594 | threadRef, | 1597 | threadRef, |
| 1595 | ]); | 1598 | ]); |
| 1599 | /* eslint-enable react/no-unstable-nested-components */ | ||
| 1596 | 1600 | ||
| 1597 | return ( | 1601 | return ( |
| 1598 | <div | 1602 | <div |
apps/web/src/components/CommandPalette.tsx+13-14| ... | @@ -138,9 +138,20 @@ import { | ... | @@ -138,9 +138,20 @@ import { |
| 138 | buildSidebarProjectPickerEntries, | 138 | buildSidebarProjectPickerEntries, |
| 139 | buildSidebarProjectSnapshots, | 139 | buildSidebarProjectSnapshots, |
| 140 | } from "../sidebarProjectGrouping"; | 140 | } from "../sidebarProjectGrouping"; |
| 141 | import type { Project } from "../types"; | ||
| 141 | 142 | ||
| 142 | const EMPTY_BROWSE_ENTRIES: FilesystemBrowseResult["entries"] = []; | 143 | const EMPTY_BROWSE_ENTRIES: FilesystemBrowseResult["entries"] = []; |
| 143 | 144 | ||
| 145 | function projectFavicon(project: Project) { | ||
| 146 | return ( | ||
| 147 | <ProjectFavicon | ||
| 148 | environmentId={project.environmentId} | ||
| 149 | cwd={project.workspaceRoot} | ||
| 150 | className={ITEM_ICON_CLASS} | ||
| 151 | /> | ||
| 152 | ); | ||
| 153 | } | ||
| 154 | |||
| 144 | function getLocalFileManagerName(platform: string): string { | 155 | function getLocalFileManagerName(platform: string): string { |
| 145 | if (isMacPlatform(platform)) { | 156 | if (isMacPlatform(platform)) { |
| 146 | return "Finder"; | 157 | return "Finder"; |
| ... | @@ -924,13 +935,7 @@ function OpenCommandPaletteDialog(props: { | ... | @@ -924,13 +935,7 @@ function OpenCommandPaletteDialog(props: { |
| 924 | group?.memberProjects.flatMap((member) => [member.title, member.workspaceRoot]) ?? [] | 935 | group?.memberProjects.flatMap((member) => [member.title, member.workspaceRoot]) ?? [] |
| 925 | ); | 936 | ); |
| 926 | }, | 937 | }, |
| 927 | icon: (project) => ( | 938 | icon: projectFavicon, |
| 928 | <ProjectFavicon | ||
| 929 | environmentId={project.environmentId} | ||
| 930 | cwd={project.workspaceRoot} | ||
| 931 | className={ITEM_ICON_CLASS} | ||
| 932 | /> | ||
| 933 | ), | ||
| 934 | runProject: openProjectFromSearch, | 939 | runProject: openProjectFromSearch, |
| 935 | }), | 940 | }), |
| 936 | [openProjectFromSearch, pickerProjects, projectGroupByTargetKey], | 941 | [openProjectFromSearch, pickerProjects, projectGroupByTargetKey], |
| ... | @@ -948,13 +953,7 @@ function OpenCommandPaletteDialog(props: { | ... | @@ -948,13 +953,7 @@ function OpenCommandPaletteDialog(props: { |
| 948 | group?.memberProjects.flatMap((member) => [member.title, member.workspaceRoot]) ?? [] | 953 | group?.memberProjects.flatMap((member) => [member.title, member.workspaceRoot]) ?? [] |
| 949 | ); | 954 | ); |
| 950 | }, | 955 | }, |
| 951 | icon: (project) => ( | 956 | icon: projectFavicon, |
| 952 | <ProjectFavicon | ||
| 953 | environmentId={project.environmentId} | ||
| 954 | cwd={project.workspaceRoot} | ||
| 955 | className={ITEM_ICON_CLASS} | ||
| 956 | /> | ||
| 957 | ), | ||
| 958 | runProject: async (project) => { | 957 | runProject: async (project) => { |
| 959 | const group = projectGroupByTargetKey.get(`${project.environmentId}:${project.id}`); | 958 | const group = projectGroupByTargetKey.get(`${project.environmentId}:${project.id}`); |
| 960 | const contextualRefBelongsToGroup = | 959 | const contextualRefBelongsToGroup = |
apps/web/src/components/settings/FontFamilyPicker.tsx-1| ... | @@ -129,7 +129,6 @@ export function FontFamilyPicker({ | ... | @@ -129,7 +129,6 @@ export function FontFamilyPicker({ |
| 129 | if (initialOpen) setOpen(true); | 129 | if (initialOpen) setOpen(true); |
| 130 | // The prop is only meaningful at mount - the control just swapped in | 130 | // The prop is only meaningful at mount - the control just swapped in |
| 131 | // under an active focus - so later changes are deliberately ignored. | 131 | // under an active focus - so later changes are deliberately ignored. |
| 132 | // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| 133 | }, []); | 132 | }, []); |
| 134 | const listRef = useRef<LegendListRef | null>(null); | 133 | const listRef = useRef<LegendListRef | null>(null); |
| 135 | const enumeration = useFontEnumeration(); | 134 | const enumeration = useFontEnumeration(); |
apps/web/src/components/settings/SettingsFontPreviews.tsx+2-2| ... | @@ -113,8 +113,8 @@ export function CodeFontPreview() { | ... | @@ -113,8 +113,8 @@ export function CodeFontPreview() { |
| 113 | if (htmlByFile === null) return null; | 113 | if (htmlByFile === null) return null; |
| 114 | return ( | 114 | return ( |
| 115 | <div className="mt-1 mb-2 space-y-2"> | 115 | <div className="mt-1 mb-2 space-y-2"> |
| 116 | {htmlByFile.map((html, index) => ( | 116 | {htmlByFile.map((html) => ( |
| 117 | <StaticDiffHtml key={index} html={html} /> | 117 | <StaticDiffHtml key={html} html={html} /> |
| 118 | ))} | 118 | ))} |
| 119 | </div> | 119 | </div> |
| 120 | ); | 120 | ); |
apps/web/src/components/settings/SettingsPanels.tsx-1| ... | @@ -116,7 +116,6 @@ import { | ... | @@ -116,7 +116,6 @@ import { |
| 116 | isMonospaceFamily, | 116 | isMonospaceFamily, |
| 117 | resolveDefaultFamilyLabel, | 117 | resolveDefaultFamilyLabel, |
| 118 | } from "../../appearanceFonts"; | 118 | } from "../../appearanceFonts"; |
| 119 | import { DEFAULT_TERMINAL_FONT_FAMILY } from "~/terminal/ghostty/surface"; | ||
| 120 | import { CodeFontPreview, PromptFontPreview, TerminalFontPreview } from "./SettingsFontPreviews"; | 119 | import { CodeFontPreview, PromptFontPreview, TerminalFontPreview } from "./SettingsFontPreviews"; |
| 121 | import { discoverInstalledFonts, FontFamilyPicker, useFontEnumeration } from "./FontFamilyPicker"; | 120 | import { discoverInstalledFonts, FontFamilyPicker, useFontEnumeration } from "./FontFamilyPicker"; |
| 122 | import { | 121 | import { |
apps/web/src/components/sidebar/SidebarUpdatePill.tsx+11-2| ... | @@ -19,6 +19,15 @@ import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; | ... | @@ -19,6 +19,15 @@ import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; |
| 19 | import { Separator } from "../ui/separator"; | 19 | import { Separator } from "../ui/separator"; |
| 20 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; | 20 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 21 | 21 | ||
| 22 | function keyReleaseNoteItems(items: ReadonlyArray<string>) { | ||
| 23 | const occurrences = new Map<string, number>(); | ||
| 24 | return items.map((item) => { | ||
| 25 | const occurrence = occurrences.get(item) ?? 0; | ||
| 26 | occurrences.set(item, occurrence + 1); | ||
| 27 | return { item, key: JSON.stringify([item, occurrence]) }; | ||
| 28 | }); | ||
| 29 | } | ||
| 30 | |||
| 22 | function SidebarUpdateReleaseNotesTooltip({ | 31 | function SidebarUpdateReleaseNotesTooltip({ |
| 23 | state, | 32 | state, |
| 24 | tooltip, | 33 | tooltip, |
| ... | @@ -44,8 +53,8 @@ function SidebarUpdateReleaseNotesTooltip({ | ... | @@ -44,8 +53,8 @@ function SidebarUpdateReleaseNotesTooltip({ |
| 44 | {index === 0 ? "What's changed" : `Changes in ${releaseNote.version}`} | 53 | {index === 0 ? "What's changed" : `Changes in ${releaseNote.version}`} |
| 45 | </h3> | 54 | </h3> |
| 46 | <ul className="mt-2 space-y-1.5 pl-4 text-xs leading-5 text-popover-foreground/90"> | 55 | <ul className="mt-2 space-y-1.5 pl-4 text-xs leading-5 text-popover-foreground/90"> |
| 47 | {releaseNote.items.map((item, itemIndex) => ( | 56 | {keyReleaseNoteItems(releaseNote.items).map(({ item, key }) => ( |
| 48 | <li className="list-disc break-words" key={`${releaseNote.version}-${itemIndex}`}> | 57 | <li className="list-disc break-words" key={key}> |
| 49 | {item} | 58 | {item} |
| 50 | </li> | 59 | </li> |
| 51 | ))} | 60 | ))} |