mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-01 14:12:51 +00:00
* fix(app): show press feedback on sidebar rows, footer icons, and settings tiles Touch has no hover, so these controls gave no acknowledgement when pressed. Rows take the workspace row's pressed fill; the sidebar header row paints it on the row so the trailing slot lights up with the button. Footer icon buttons take the round header-control highlight. * style(app): format sidebar header row * fix(app): keep footer icon corners tappable on web Web hit-testing follows border-radius, so rounding the footer buttons turned their 44pt square targets into circles and taps near the corners fell through. Paint the round highlight as a layer inside the square button instead.
209 lines
7.3 KiB
TypeScript
209 lines
7.3 KiB
TypeScript
import { useCallback, useState } from "react";
|
|
import { Text, View } from "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";
|
|
import { GitHubIcon } from "@/components/icons/github-icon";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuHint,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import { DensityIcon } from "@/components/ui/density-icon";
|
|
import { SidebarFooterIconHighlight } from "./sidebar-footer-icon-highlight";
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
import { useAppDiagnosticStore } from "@/diagnostics/store";
|
|
import { useKeyboardShortcutsAvailable } from "@/keyboard/availability";
|
|
import { useHostRuntimeIsConnected, useHosts } from "@/runtime/host-runtime";
|
|
import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store";
|
|
import { useSessionStore } from "@/stores/session-store";
|
|
import { density } from "@/styles/density";
|
|
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 { openChangelog } from "@/changelog";
|
|
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 ThemedActivity = withUnistyles(Activity);
|
|
const ThemedGift = withUnistyles(Gift);
|
|
const ThemedKeyboard = withUnistyles(Keyboard);
|
|
const ThemedDiscordIcon = withUnistyles(DiscordIcon);
|
|
const ThemedGitHubIcon = withUnistyles(GitHubIcon);
|
|
const foregroundMutedColorMapping = (theme: Theme) => ({
|
|
color: theme.colors.foregroundMuted,
|
|
});
|
|
const diagnosticLeadingIcon = (
|
|
<ThemedActivity size={ICON_SIZE.sm} uniProps={foregroundMutedColorMapping} />
|
|
);
|
|
const shortcutsLeadingIcon = (
|
|
<ThemedKeyboard size={ICON_SIZE.sm} uniProps={foregroundMutedColorMapping} />
|
|
);
|
|
const discordLeadingIcon = (
|
|
<ThemedDiscordIcon size={ICON_SIZE.sm} uniProps={foregroundMutedColorMapping} />
|
|
);
|
|
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}
|
|
trailing={version}
|
|
testID={`sidebar-help-host-version-${host.serverId}`}
|
|
>
|
|
{host.label}
|
|
</DropdownMenuHint>
|
|
);
|
|
}
|
|
|
|
export function SidebarHelpMenu() {
|
|
const { t } = useTranslation();
|
|
const shortcutsAvailable = useKeyboardShortcutsAvailable();
|
|
const openAppDiagnostic = useAppDiagnosticStore((state) => state.open);
|
|
const setShortcutsDialogOpen = useKeyboardShortcutsStore((state) => state.setShortcutsDialogOpen);
|
|
const [open, setOpen] = useState(false);
|
|
const version = formatVersionWithPrefix(resolveAppVersion());
|
|
const hosts = useHosts();
|
|
|
|
const openKeyboardShortcuts = useCallback(() => {
|
|
setShortcutsDialogOpen(true);
|
|
}, [setShortcutsDialogOpen]);
|
|
|
|
const openDiscord = useCallback(() => {
|
|
void openExternalUrl(DISCORD_URL);
|
|
}, []);
|
|
|
|
const openGitHubIssue = useCallback(() => {
|
|
void openExternalUrl(GITHUB_ISSUE_URL);
|
|
}, []);
|
|
|
|
return (
|
|
<DropdownMenu open={open} onOpenChange={setOpen}>
|
|
<Tooltip delayDuration={300} enabledOnDesktop={!open}>
|
|
<TooltipTrigger asChild>
|
|
<View>
|
|
<DropdownMenuTrigger
|
|
style={styles.trigger}
|
|
testID="sidebar-help"
|
|
accessibilityRole="button"
|
|
accessibilityLabel={t("sidebar.help.trigger")}
|
|
>
|
|
{({ hovered, pressed, open: menuOpen }) => (
|
|
<>
|
|
<SidebarFooterIconHighlight visible={pressed || menuOpen} />
|
|
<DensityIcon
|
|
icon={CircleHelp}
|
|
size="md"
|
|
color={hovered ? "foreground" : "foregroundMuted"}
|
|
/>
|
|
</>
|
|
)}
|
|
</DropdownMenuTrigger>
|
|
</View>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="top" align="center" offset={8}>
|
|
<Text style={styles.tooltipText}>{t("sidebar.help.trigger")}</Text>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
<DropdownMenuContent side="top" align="end" offset={8} width={280} testID="sidebar-help-menu">
|
|
<DropdownMenuLabel>{t("sidebar.help.sectionHelp")}</DropdownMenuLabel>
|
|
{shortcutsAvailable ? (
|
|
<DropdownMenuItem
|
|
testID="sidebar-help-shortcuts"
|
|
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"
|
|
leading={discordLeadingIcon}
|
|
onSelect={openDiscord}
|
|
>
|
|
{t("sidebar.help.discord")}
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
testID="sidebar-help-github"
|
|
leading={githubLeadingIcon}
|
|
onSelect={openGitHubIssue}
|
|
>
|
|
{t("sidebar.help.github")}
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<View style={styles.versionList}>
|
|
<DropdownMenuHint
|
|
style={styles.versionHint}
|
|
trailing={version}
|
|
testID="sidebar-help-version"
|
|
>
|
|
{t("sidebar.help.appName")}
|
|
</DropdownMenuHint>
|
|
{hosts.map((host) => (
|
|
<HostVersionHint key={host.serverId} host={host} />
|
|
))}
|
|
</View>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create((theme) => ({
|
|
trigger: {
|
|
width: density.iconButton,
|
|
height: density.iconButton,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
paddingVertical: theme.spacing[1],
|
|
paddingHorizontal: theme.spacing[1],
|
|
},
|
|
tooltipText: {
|
|
fontSize: theme.fontSize.base,
|
|
color: theme.colors.popoverForeground,
|
|
},
|
|
versionList: {
|
|
gap: theme.spacing[1],
|
|
paddingVertical: theme.spacing[2],
|
|
},
|
|
versionHint: {
|
|
paddingVertical: 0,
|
|
},
|
|
}));
|