feat(app): add community links and sidebar home button
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { useCallback } from "react";
|
||||
import { View } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { Heart } from "lucide-react-native";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { GitHubIcon } from "@/components/icons/github-icon";
|
||||
import { DiscordIcon } from "@/components/icons/discord-icon";
|
||||
import { openExternalUrl } from "@/utils/open-external-url";
|
||||
|
||||
const renderGitHubIcon = (color: string) => <GitHubIcon color={color} size={14} />;
|
||||
const renderDiscordIcon = (color: string) => <DiscordIcon color={color} size={14} />;
|
||||
|
||||
export function CommunityLinks() {
|
||||
const handleOpenGitHub = useCallback(() => {
|
||||
void openExternalUrl("https://github.com/getpaseo/paseo");
|
||||
}, []);
|
||||
|
||||
const handleOpenSponsor = useCallback(() => {
|
||||
void openExternalUrl("https://github.com/sponsors/boudra");
|
||||
}, []);
|
||||
|
||||
const handleOpenDiscord = useCallback(() => {
|
||||
void openExternalUrl("https://discord.gg/jz8T2uahpH");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
leftIcon={renderGitHubIcon}
|
||||
onPress={handleOpenGitHub}
|
||||
testID="community-links-github-star"
|
||||
>
|
||||
Star
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
leftIcon={Heart}
|
||||
onPress={handleOpenSponsor}
|
||||
testID="community-links-sponsor"
|
||||
>
|
||||
Sponsor
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
leftIcon={renderDiscordIcon}
|
||||
onPress={handleOpenDiscord}
|
||||
testID="community-links-discord"
|
||||
>
|
||||
Community
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create(() => ({
|
||||
row: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: 0,
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,14 @@
|
||||
import Svg, { Path } from "react-native-svg";
|
||||
|
||||
interface DiscordIconProps {
|
||||
size?: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export function DiscordIcon({ size = 16, color = "currentColor" }: DiscordIconProps) {
|
||||
return (
|
||||
<Svg width={size} height={size} viewBox="0 0 24 24" fill={color}>
|
||||
<Path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" />
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { router, usePathname } from "expo-router";
|
||||
import { FolderPlus, MessagesSquare, Settings, X } from "lucide-react-native";
|
||||
import { FolderPlus, Home, MessagesSquare, Settings, X } from "lucide-react-native";
|
||||
import {
|
||||
type Dispatch,
|
||||
memo,
|
||||
@@ -58,6 +58,7 @@ import { resolveActiveHost } from "@/utils/active-host";
|
||||
import { formatConnectionStatus } from "@/utils/daemons";
|
||||
import { useWindowControlsPadding } from "@/utils/desktop-window";
|
||||
import {
|
||||
buildHostOpenProjectRoute,
|
||||
buildHostSessionsRoute,
|
||||
buildSettingsRoute,
|
||||
mapPathnameToServer,
|
||||
@@ -94,6 +95,7 @@ interface SidebarSharedProps {
|
||||
handleRefresh: () => void;
|
||||
handleHostSelect: (nextServerId: string) => void;
|
||||
handleOpenProject: () => void;
|
||||
handleHome: () => void;
|
||||
handleSettings: () => void;
|
||||
renderHostOption: (input: {
|
||||
option: ComboboxOption;
|
||||
@@ -223,6 +225,17 @@ export const LeftSidebar = memo(function LeftSidebar({
|
||||
router.push(buildSettingsRoute());
|
||||
}, []);
|
||||
|
||||
const handleHomeMobile = useCallback(() => {
|
||||
if (!activeServerId) return;
|
||||
showMobileAgent();
|
||||
router.push(buildHostOpenProjectRoute(activeServerId));
|
||||
}, [activeServerId, showMobileAgent]);
|
||||
|
||||
const handleHomeDesktop = useCallback(() => {
|
||||
if (!activeServerId) return;
|
||||
router.push(buildHostOpenProjectRoute(activeServerId));
|
||||
}, [activeServerId]);
|
||||
|
||||
const handleViewMoreNavigate = useCallback(() => {
|
||||
if (!activeServerId) {
|
||||
return;
|
||||
@@ -272,6 +285,7 @@ export const LeftSidebar = memo(function LeftSidebar({
|
||||
isOpen={isOpen}
|
||||
closeToAgent={showMobileAgent}
|
||||
handleOpenProject={handleOpenProjectMobile}
|
||||
handleHome={handleHomeMobile}
|
||||
handleSettings={handleSettingsMobile}
|
||||
handleViewMoreNavigate={handleViewMoreNavigate}
|
||||
/>
|
||||
@@ -284,6 +298,7 @@ export const LeftSidebar = memo(function LeftSidebar({
|
||||
insetsTop={insets.top}
|
||||
isOpen={isOpen}
|
||||
handleOpenProject={handleOpenProjectDesktop}
|
||||
handleHome={handleHomeDesktop}
|
||||
handleSettings={handleSettingsDesktop}
|
||||
handleViewMore={handleViewMoreNavigate}
|
||||
/>
|
||||
@@ -414,6 +429,7 @@ function SidebarFooter({
|
||||
handleHostSelect,
|
||||
renderHostOption,
|
||||
handleOpenProject,
|
||||
handleHome,
|
||||
handleSettings,
|
||||
}: {
|
||||
theme: SidebarTheme;
|
||||
@@ -427,6 +443,7 @@ function SidebarFooter({
|
||||
handleHostSelect: (nextServerId: string) => void;
|
||||
renderHostOption: SidebarSharedProps["renderHostOption"];
|
||||
handleOpenProject: () => void;
|
||||
handleHome: () => void;
|
||||
handleSettings: () => void;
|
||||
}) {
|
||||
const newAgentKeys = useShortcutKeys("new-agent");
|
||||
@@ -456,6 +473,13 @@ function SidebarFooter({
|
||||
<AddProjectTooltipContent newAgentKeys={newAgentKeys} />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<FooterIconButton
|
||||
onPress={handleHome}
|
||||
testID="sidebar-home"
|
||||
accessibilityLabel="Home"
|
||||
icon={Home}
|
||||
theme={theme}
|
||||
/>
|
||||
<FooterIconButton
|
||||
onPress={handleSettings}
|
||||
testID="sidebar-settings"
|
||||
@@ -501,6 +525,7 @@ function MobileSidebar({
|
||||
handleHostSelect,
|
||||
renderHostOption,
|
||||
handleOpenProject,
|
||||
handleHome,
|
||||
handleSettings,
|
||||
insetsTop,
|
||||
insetsBottom,
|
||||
@@ -729,6 +754,7 @@ function MobileSidebar({
|
||||
handleHostSelect={handleHostSelect}
|
||||
renderHostOption={renderHostOption}
|
||||
handleOpenProject={handleOpenProject}
|
||||
handleHome={handleHome}
|
||||
handleSettings={handleSettings}
|
||||
/>
|
||||
</View>
|
||||
@@ -758,6 +784,7 @@ function DesktopSidebar({
|
||||
handleHostSelect,
|
||||
renderHostOption,
|
||||
handleOpenProject,
|
||||
handleHome,
|
||||
handleSettings,
|
||||
insetsTop,
|
||||
isOpen,
|
||||
@@ -871,6 +898,7 @@ function DesktopSidebar({
|
||||
handleHostSelect={handleHostSelect}
|
||||
renderHostOption={renderHostOption}
|
||||
handleOpenProject={handleOpenProject}
|
||||
handleHome={handleHome}
|
||||
handleSettings={handleSettings}
|
||||
/>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { useRouter } from "expo-router";
|
||||
import { FolderOpen, Inbox, Plug, Smartphone } from "lucide-react-native";
|
||||
import { PaseoLogo } from "@/components/icons/paseo-logo";
|
||||
import { CommunityLinks } from "@/components/community-links";
|
||||
import { MenuHeader } from "@/components/headers/menu-header";
|
||||
import { useOpenProjectPicker } from "@/hooks/use-open-project-picker";
|
||||
import { usePanelStore } from "@/stores/panel-store";
|
||||
@@ -106,6 +107,9 @@ export function OpenProjectScreen({ serverId }: { serverId: string }) {
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.communityRow}>
|
||||
<CommunityLinks />
|
||||
</View>
|
||||
<PairDeviceModal
|
||||
visible={isPairDeviceOpen}
|
||||
onClose={handleClosePairDevice}
|
||||
@@ -227,4 +231,17 @@ const styles = StyleSheet.create((theme) => ({
|
||||
fontSize: theme.fontSize.sm,
|
||||
lineHeight: 18,
|
||||
},
|
||||
communityRow: {
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: {
|
||||
xs: HEADER_INNER_HEIGHT_MOBILE + HEADER_TOP_PADDING_MOBILE + theme.spacing[2],
|
||||
md: HEADER_INNER_HEIGHT + theme.spacing[2],
|
||||
},
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: 0,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -56,6 +56,7 @@ import { AddHostModal } from "@/components/add-host-modal";
|
||||
import { PairLinkModal } from "@/components/pair-link-modal";
|
||||
import { KeyboardShortcutsSection } from "@/screens/settings/keyboard-shortcuts-section";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CommunityLinks } from "@/components/community-links";
|
||||
import { SegmentedControl } from "@/components/ui/segmented-control";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -457,6 +458,9 @@ function AboutSection({ appVersionText, isDesktopApp }: AboutSectionProps) {
|
||||
</View>
|
||||
{isDesktopApp ? <DesktopAppUpdateRow /> : null}
|
||||
</View>
|
||||
<View style={styles.aboutCommunity}>
|
||||
<CommunityLinks />
|
||||
</View>
|
||||
</SettingsSection>
|
||||
);
|
||||
}
|
||||
@@ -1267,6 +1271,9 @@ const styles = StyleSheet.create((theme) => ({
|
||||
fontSize: theme.fontSize.xs,
|
||||
marginTop: theme.spacing[1],
|
||||
},
|
||||
aboutCommunity: {
|
||||
marginTop: theme.spacing[4],
|
||||
},
|
||||
aboutUpdateActions: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
|
||||
Reference in New Issue
Block a user