| 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 | 1363 | }, |
| 1364 | 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 | 1369 | const markdownComponents = useMemo<Components>(() => { |
| 1367 | 1370 | const fileLinkChip = ( |
| 1368 | 1371 | fileLinkMeta: MarkdownFileLinkMeta, |
| ... | ... | @@ -1593,6 +1596,7 @@ function ChatMarkdown({ |
| 1593 | 1596 | text, |
| 1594 | 1597 | threadRef, |
| 1595 | 1598 | ]); |
| 1599 | /* eslint-enable react/no-unstable-nested-components */ | |
| 1596 | 1600 | |
| 1597 | 1601 | return ( |
| 1598 | 1602 | <div |
apps/web/src/components/CommandPalette.tsx+13-14| ... | ... | @@ -138,9 +138,20 @@ import { |
| 138 | 138 | buildSidebarProjectPickerEntries, |
| 139 | 139 | buildSidebarProjectSnapshots, |
| 140 | 140 | } from "../sidebarProjectGrouping"; |
| 141 | import type { Project } from "../types"; | |
| 141 | 142 | |
| 142 | 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 | 155 | function getLocalFileManagerName(platform: string): string { |
| 145 | 156 | if (isMacPlatform(platform)) { |
| 146 | 157 | return "Finder"; |
| ... | ... | @@ -924,13 +935,7 @@ function OpenCommandPaletteDialog(props: { |
| 924 | 935 | group?.memberProjects.flatMap((member) => [member.title, member.workspaceRoot]) ?? [] |
| 925 | 936 | ); |
| 926 | 937 | }, |
| 927 | icon: (project) => ( | |
| 928 | <ProjectFavicon | |
| 929 | environmentId={project.environmentId} | |
| 930 | cwd={project.workspaceRoot} | |
| 931 | className={ITEM_ICON_CLASS} | |
| 932 | /> | |
| 933 | ), | |
| 938 | icon: projectFavicon, | |
| 934 | 939 | runProject: openProjectFromSearch, |
| 935 | 940 | }), |
| 936 | 941 | [openProjectFromSearch, pickerProjects, projectGroupByTargetKey], |
| ... | ... | @@ -948,13 +953,7 @@ function OpenCommandPaletteDialog(props: { |
| 948 | 953 | group?.memberProjects.flatMap((member) => [member.title, member.workspaceRoot]) ?? [] |
| 949 | 954 | ); |
| 950 | 955 | }, |
| 951 | icon: (project) => ( | |
| 952 | <ProjectFavicon | |
| 953 | environmentId={project.environmentId} | |
| 954 | cwd={project.workspaceRoot} | |
| 955 | className={ITEM_ICON_CLASS} | |
| 956 | /> | |
| 957 | ), | |
| 956 | icon: projectFavicon, | |
| 958 | 957 | runProject: async (project) => { |
| 959 | 958 | const group = projectGroupByTargetKey.get(`${project.environmentId}:${project.id}`); |
| 960 | 959 | const contextualRefBelongsToGroup = |
apps/web/src/components/settings/FontFamilyPicker.tsx-1| ... | ... | @@ -129,7 +129,6 @@ export function FontFamilyPicker({ |
| 129 | 129 | if (initialOpen) setOpen(true); |
| 130 | 130 | // The prop is only meaningful at mount - the control just swapped in |
| 131 | 131 | // under an active focus - so later changes are deliberately ignored. |
| 132 | // eslint-disable-next-line react-hooks/exhaustive-deps | |
| 133 | 132 | }, []); |
| 134 | 133 | const listRef = useRef<LegendListRef | null>(null); |
| 135 | 134 | const enumeration = useFontEnumeration(); |
apps/web/src/components/settings/SettingsFontPreviews.tsx+2-2| ... | ... | @@ -113,8 +113,8 @@ export function CodeFontPreview() { |
| 113 | 113 | if (htmlByFile === null) return null; |
| 114 | 114 | return ( |
| 115 | 115 | <div className="mt-1 mb-2 space-y-2"> |
| 116 | {htmlByFile.map((html, index) => ( | |
| 117 | <StaticDiffHtml key={index} html={html} /> | |
| 116 | {htmlByFile.map((html) => ( | |
| 117 | <StaticDiffHtml key={html} html={html} /> | |
| 118 | 118 | ))} |
| 119 | 119 | </div> |
| 120 | 120 | ); |
apps/web/src/components/settings/SettingsPanels.tsx-1| ... | ... | @@ -116,7 +116,6 @@ import { |
| 116 | 116 | isMonospaceFamily, |
| 117 | 117 | resolveDefaultFamilyLabel, |
| 118 | 118 | } from "../../appearanceFonts"; |
| 119 | import { DEFAULT_TERMINAL_FONT_FAMILY } from "~/terminal/ghostty/surface"; | |
| 120 | 119 | import { CodeFontPreview, PromptFontPreview, TerminalFontPreview } from "./SettingsFontPreviews"; |
| 121 | 120 | import { discoverInstalledFonts, FontFamilyPicker, useFontEnumeration } from "./FontFamilyPicker"; |
| 122 | 121 | import { |
apps/web/src/components/sidebar/SidebarUpdatePill.tsx+11-2| ... | ... | @@ -19,6 +19,15 @@ import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; |
| 19 | 19 | import { Separator } from "../ui/separator"; |
| 20 | 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 | 31 | function SidebarUpdateReleaseNotesTooltip({ |
| 23 | 32 | state, |
| 24 | 33 | tooltip, |
| ... | ... | @@ -44,8 +53,8 @@ function SidebarUpdateReleaseNotesTooltip({ |
| 44 | 53 | {index === 0 ? "What's changed" : `Changes in ${releaseNote.version}`} |
| 45 | 54 | </h3> |
| 46 | 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) => ( | |
| 48 | <li className="list-disc break-words" key={`${releaseNote.version}-${itemIndex}`}> | |
| 56 | {keyReleaseNoteItems(releaseNote.items).map(({ item, key }) => ( | |
| 57 | <li className="list-disc break-words" key={key}> | |
| 49 | 58 | {item} |
| 50 | 59 | </li> |
| 51 | 60 | ))} |