Polish release notes and in-app help (#2070)

* feat(ui): improve changelog and help navigation

Make release notes easier to scan and reach from the app. Also keep the homepage marquee within the layout viewport so it cannot create horizontal scrolling.

* fix(website): reject duplicate release anchors
This commit is contained in:
Mohamed Boudra
2026-07-14 21:06:25 +02:00
committed by GitHub
parent cd6c608c9e
commit d781b68711
14 changed files with 310 additions and 110 deletions
@@ -1,6 +1,6 @@
import { useCallback, useState } from "react";
import { Text, View } from "react-native";
import { Activity, CircleHelp, Keyboard } from "lucide-react-native";
import { Activity, CircleHelp, Gift, Keyboard } from "lucide-react-native";
import { useTranslation } from "react-i18next";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
import { DiscordIcon } from "@/components/icons/discord-icon";
@@ -18,16 +18,21 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
import { useIsCompactFormFactor } from "@/constants/layout";
import { isNative } from "@/constants/platform";
import { useAppDiagnosticStore } from "@/diagnostics/store";
import { useHostRuntimeIsConnected, useHosts } from "@/runtime/host-runtime";
import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store";
import { useSessionStore } from "@/stores/session-store";
import { ICON_SIZE, type Theme } from "@/styles/theme";
import type { HostProfile } from "@/types/host-connection";
import { formatVersionWithPrefix } from "@/desktop/updates/desktop-updates";
import { resolveAppVersion } from "@/utils/app-version";
import { openExternalUrl } from "@/utils/open-external-url";
const DISCORD_URL = "https://discord.gg/jz8T2uahpH";
const GITHUB_ISSUE_URL = "https://github.com/getpaseo/paseo/issues/new";
const CHANGELOG_URL = "https://paseo.sh/changelog";
const ThemedActivity = withUnistyles(Activity);
const ThemedCircleHelp = withUnistyles(CircleHelp);
const ThemedGift = withUnistyles(Gift);
const ThemedKeyboard = withUnistyles(Keyboard);
const ThemedDiscordIcon = withUnistyles(DiscordIcon);
const ThemedGitHubIcon = withUnistyles(GitHubIcon);
@@ -47,6 +52,29 @@ const discordLeadingIcon = (
const githubLeadingIcon = (
<ThemedGitHubIcon size={ICON_SIZE.sm} uniProps={foregroundMutedColorMapping} />
);
const changelogLeadingIcon = (
<ThemedGift size={ICON_SIZE.sm} uniProps={foregroundMutedColorMapping} />
);
function HostVersionHint({ host }: { host: HostProfile }) {
const { t } = useTranslation();
const isConnected = useHostRuntimeIsConnected(host.serverId);
const daemonVersion = useSessionStore(
(state) => state.sessions[host.serverId]?.serverInfo?.version ?? null,
);
const version = isConnected
? formatVersionWithPrefix(daemonVersion)
: t("settings.about.offline");
return (
<DropdownMenuHint
style={styles.versionHint}
testID={`sidebar-help-host-version-${host.serverId}`}
>
{host.label} {version}
</DropdownMenuHint>
);
}
export function SidebarHelpMenu() {
const { t } = useTranslation();
@@ -56,6 +84,7 @@ export function SidebarHelpMenu() {
const [open, setOpen] = useState(false);
const showKeyboardShortcuts = !isNative && !isCompactLayout;
const version = formatVersionWithPrefix(resolveAppVersion());
const hosts = useHosts();
const openKeyboardShortcuts = useCallback(() => {
setShortcutsDialogOpen(true);
@@ -69,6 +98,10 @@ export function SidebarHelpMenu() {
void openExternalUrl(GITHUB_ISSUE_URL);
}, []);
const openChangelog = useCallback(() => {
void openExternalUrl(CHANGELOG_URL);
}, []);
return (
<DropdownMenu open={open} onOpenChange={setOpen}>
<Tooltip delayDuration={300} enabledOnDesktop={!open}>
@@ -94,30 +127,34 @@ export function SidebarHelpMenu() {
</TooltipContent>
</Tooltip>
<DropdownMenuContent side="top" align="end" offset={8} width={280} testID="sidebar-help-menu">
<DropdownMenuLabel>{t("sidebar.help.troubleshoot")}</DropdownMenuLabel>
<DropdownMenuItem
testID="sidebar-help-diagnostics"
description={t("sidebar.help.diagnosticsDescription")}
leading={diagnosticLeadingIcon}
onSelect={openAppDiagnostic}
>
{t("sidebar.help.diagnostics")}
</DropdownMenuItem>
<DropdownMenuLabel>{t("sidebar.help.sectionHelp")}</DropdownMenuLabel>
{showKeyboardShortcuts ? (
<DropdownMenuItem
testID="sidebar-help-shortcuts"
description={t("sidebar.help.shortcutsDescription")}
leading={shortcutsLeadingIcon}
onSelect={openKeyboardShortcuts}
>
{t("sidebar.help.shortcuts")}
</DropdownMenuItem>
) : null}
<DropdownMenuItem
testID="sidebar-help-changelog"
leading={changelogLeadingIcon}
onSelect={openChangelog}
>
{t("sidebar.help.whatsNew")}
</DropdownMenuItem>
<DropdownMenuItem
testID="sidebar-help-diagnostics"
leading={diagnosticLeadingIcon}
onSelect={openAppDiagnostic}
>
{t("sidebar.help.diagnostics")}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>{t("sidebar.help.reportIssue")}</DropdownMenuLabel>
<DropdownMenuItem
testID="sidebar-help-discord"
description={t("sidebar.help.discordDescription")}
leading={discordLeadingIcon}
onSelect={openDiscord}
>
@@ -125,16 +162,20 @@ export function SidebarHelpMenu() {
</DropdownMenuItem>
<DropdownMenuItem
testID="sidebar-help-github"
description={t("sidebar.help.githubDescription")}
leading={githubLeadingIcon}
onSelect={openGitHubIssue}
>
{t("sidebar.help.github")}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuHint testID="sidebar-help-version">
{t("sidebar.help.version", { version })}
</DropdownMenuHint>
<View style={styles.versionList}>
<DropdownMenuHint style={styles.versionHint} testID="sidebar-help-version">
{t("sidebar.help.version", { version })}
</DropdownMenuHint>
{hosts.map((host) => (
<HostVersionHint key={host.serverId} host={host} />
))}
</View>
</DropdownMenuContent>
</DropdownMenu>
);
@@ -153,4 +194,11 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.sm,
color: theme.colors.popoverForeground,
},
versionList: {
gap: theme.spacing[1],
paddingVertical: theme.spacing[2],
},
versionHint: {
paddingVertical: 0,
},
}));
@@ -675,10 +675,12 @@ export function DropdownMenuSeparator({
export function DropdownMenuHint({
children,
style,
testID,
}: PropsWithChildren<{ testID?: string }>): ReactElement {
}: PropsWithChildren<{ style?: ViewStyle | ViewStyle[]; testID?: string }>): ReactElement {
const hintContainerStyle = useMemo(() => [styles.hintContainer, style], [style]);
return (
<View style={styles.hintContainer} testID={testID}>
<View style={hintContainerStyle} testID={testID}>
<Text style={styles.hintText}>{children}</Text>
</View>
);
@@ -908,7 +910,7 @@ const styles = StyleSheet.create((theme) => ({
},
hintContainer: {
paddingHorizontal: theme.spacing[3],
paddingBottom: theme.spacing[2],
paddingVertical: theme.spacing[2],
},
hintText: {
fontSize: theme.fontSize.xs,
+2 -5
View File
@@ -792,16 +792,13 @@ export const ar: TranslationResources = {
},
help: {
trigger: "المساعدة والدعم",
troubleshoot: "استكشاف الأخطاء وإصلاحها",
sectionHelp: "المساعدة",
diagnostics: "تشغيل التشخيص",
diagnosticsDescription: "جمع تفاصيل التطبيق والمضيفين المتصلين",
shortcuts: "اختصارات لوحة المفاتيح",
shortcutsDescription: "عرض اختصارات لوحة المفاتيح المتاحة",
reportIssue: "الإبلاغ عن مشكلة",
discord: "Discord",
discordDescription: "الأفضل للمساعدة السريعة والنقاش",
github: "إنشاء مشكلة على GitHub",
githubDescription: "الإبلاغ عن خطأ يمكن إعادة إنتاجه",
whatsNew: "ما الجديد",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -799,16 +799,13 @@ export const en = {
},
help: {
trigger: "Help and support",
troubleshoot: "Troubleshoot",
sectionHelp: "Help",
diagnostics: "Run diagnostics",
diagnosticsDescription: "Collect app and connected host details",
shortcuts: "Keyboard shortcuts",
shortcutsDescription: "View available keyboard shortcuts",
reportIssue: "Report an issue",
discord: "Discord",
discordDescription: "Best for quick help and discussion",
github: "Create GitHub issue",
githubDescription: "Report a reproducible bug",
whatsNew: "What's new",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -819,16 +819,13 @@ export const es: TranslationResources = {
},
help: {
trigger: "Ayuda y soporte",
troubleshoot: "Solucionar problemas",
sectionHelp: "Ayuda",
diagnostics: "Ejecutar diagnóstico",
diagnosticsDescription: "Recopila datos de la app y los hosts conectados",
shortcuts: "Atajos de teclado",
shortcutsDescription: "Ver los atajos de teclado disponibles",
reportIssue: "Informar de un problema",
discord: "Discord",
discordDescription: "La mejor opción para ayuda rápida y conversación",
github: "Crear incidencia en GitHub",
githubDescription: "Informar de un error reproducible",
whatsNew: "Novedades",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -818,16 +818,13 @@ export const fr: TranslationResources = {
},
help: {
trigger: "Aide et assistance",
troubleshoot: "Dépannage",
sectionHelp: "Aide",
diagnostics: "Lancer le diagnostic",
diagnosticsDescription: "Collecter les détails de l’app et des hôtes connectés",
shortcuts: "Raccourcis clavier",
shortcutsDescription: "Afficher les raccourcis clavier disponibles",
reportIssue: "Signaler un problème",
discord: "Discord",
discordDescription: "Idéal pour obtenir une aide rapide et échanger",
github: "Créer un ticket GitHub",
githubDescription: "Signaler un bug reproductible",
whatsNew: "Nouveautés",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -804,16 +804,13 @@ export const ja: TranslationResources = {
},
help: {
trigger: "ヘルプとサポート",
troubleshoot: "トラブルシューティング",
sectionHelp: "ヘルプ",
diagnostics: "診断を実行",
diagnosticsDescription: "アプリと接続中のホストの詳細を収集",
shortcuts: "キーボードショートカット",
shortcutsDescription: "利用可能なキーボードショートカットを表示",
reportIssue: "問題を報告",
discord: "Discord",
discordDescription: "すばやいサポートや相談に最適",
github: "GitHub Issueを作成",
githubDescription: "再現可能なバグを報告",
whatsNew: "新着情報",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -810,16 +810,13 @@ export const ptBR: TranslationResources = {
},
help: {
trigger: "Ajuda e suporte",
troubleshoot: "Resolver problemas",
sectionHelp: "Ajuda",
diagnostics: "Executar diagnóstico",
diagnosticsDescription: "Coletar detalhes do app e dos hosts conectados",
shortcuts: "Atalhos de teclado",
shortcutsDescription: "Ver os atalhos de teclado disponíveis",
reportIssue: "Relatar um problema",
discord: "Discord",
discordDescription: "Ideal para ajuda rápida e conversa",
github: "Criar issue no GitHub",
githubDescription: "Relatar um bug reproduzível",
whatsNew: "Novidades",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -811,16 +811,13 @@ export const ru: TranslationResources = {
},
help: {
trigger: "Помощь и поддержка",
troubleshoot: "Устранение неполадок",
sectionHelp: "Помощь",
diagnostics: "Запустить диагностику",
diagnosticsDescription: "Собрать данные приложения и подключённых хостов",
shortcuts: "Сочетания клавиш",
shortcutsDescription: "Показать доступные сочетания клавиш",
reportIssue: "Сообщить о проблеме",
discord: "Discord",
discordDescription: "Для быстрой помощи и обсуждения",
github: "Создать issue в GitHub",
githubDescription: "Сообщить о воспроизводимой ошибке",
whatsNew: "Что нового",
version: "Paseo {{version}}",
},
sections: {
+2 -5
View File
@@ -787,16 +787,13 @@ export const zhCN: TranslationResources = {
},
help: {
trigger: "帮助与支持",
troubleshoot: "问题排查",
sectionHelp: "帮助",
diagnostics: "运行诊断",
diagnosticsDescription: "收集应用和已连接 Host 的详细信息",
shortcuts: "键盘快捷键",
shortcutsDescription: "查看可用的键盘快捷键",
reportIssue: "报告问题",
discord: "Discord",
discordDescription: "适合快速求助和讨论",
github: "创建 GitHub Issue",
githubDescription: "报告可复现的 bug",
whatsNew: "新功能",
version: "Paseo {{version}}",
},
sections: {