Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions apps/apollo-vertex/app/vertex-components/shell/page.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { ShellTemplate } from '@/templates/ShellTemplate';

# Shell

A component that includes OAuth2 authentication and a collapsible sidebar.

<div className="not-prose my-8 rounded-lg overflow-hidden" style={{ height: '600px' }}>
<div className="[&_.h-screen]:!h-full h-full">
<ShellTemplate />
</div>
<iframe src="/preview/shell/dashboard" className="w-full h-full border-0" />
</div>

<a href="/preview/shell/dashboard" target="_blank" rel="noopener noreferrer">Open standalone preview ↗</a>
Expand All @@ -17,9 +13,7 @@ A component that includes OAuth2 authentication and a collapsible sidebar.
Use the `variant="minimal"` prop to render a horizontal header layout instead of the default sidebar.

<div className="not-prose my-8 rounded-lg overflow-hidden" style={{ height: '600px' }}>
<div className="[&_.h-screen]:!h-full h-full">
<ShellTemplate variant="minimal" />
</div>
<iframe src="/preview/shell-minimal" className="w-full h-full border-0" />
</div>

<a href="/preview/shell-minimal" target="_blank" rel="noopener noreferrer">Open standalone preview ↗</a>
Expand All @@ -43,6 +37,7 @@ The `ApolloShell` component must be wrapped in a `QueryClientProvider` from `@ta

```tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Link, useLocation } from '@tanstack/react-router';
import { Home, Settings } from 'lucide-react';
import { ApolloShell } from '@/components/ui/shell';

Expand All @@ -54,6 +49,8 @@ const navItems = [
];

function App() {
const { pathname } = useLocation();

return (
<QueryClientProvider client={queryClient}>
<ApolloShell
Expand All @@ -63,6 +60,8 @@ function App() {
companyName="Your Company"
productName="Your Product"
navItems={navItems}
linkComponent={Link}
pathname={pathname}
>
{/* your authenticated app content */}
<YourApp />
Expand Down
1 change: 0 additions & 1 deletion apps/apollo-vertex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"@tailwindcss/postcss": "^4.1.17",
"@tanstack/react-query": "^5.90.21",
"@tanstack/react-table": "^8.21.3",
"@tanstack/react-router": "^1.132.31",
"@uidotdev/usehooks": "^2.4.1",
"@vercel/analytics": "^1.5.0",
"class-variance-authority": "^0.7.1",
Expand Down
4 changes: 4 additions & 0 deletions apps/apollo-vertex/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,10 @@
],
"files": [
{ "path": "registry/shell/shell.tsx", "type": "registry:ui" },
{
"path": "registry/shell/shell-router-context.tsx",
"type": "registry:ui"
},
{
"path": "registry/shell/shell-layout.tsx",
"type": "registry:ui"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link, useLocation } from "@tanstack/react-router";
import { cn } from "@/lib/utils";
import { ShellLink, useShellPathname } from "./shell-router-context";
import { Text } from "./shell-text";
import type { TranslationKey } from "./shell-translation-key";

Expand All @@ -9,11 +9,11 @@ interface MinimalNavItemProps {
}

export const MinimalNavItem = ({ to, label }: MinimalNavItemProps) => {
const { pathname } = useLocation();
const pathname = useShellPathname();
const isActive = pathname === to;

return (
<Link
<ShellLink
to={to}
className={cn(
"px-4 py-1.5 rounded-full text-sm font-medium transition-colors duration-200 shrink-0 whitespace-nowrap",
Expand All @@ -23,6 +23,6 @@ export const MinimalNavItem = ({ to, label }: MinimalNavItemProps) => {
)}
>
<Text value={label} />
</Link>
</ShellLink>
);
};
8 changes: 4 additions & 4 deletions apps/apollo-vertex/registry/shell/shell-nav-item.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Link, useLocation } from "@tanstack/react-router";
import { useLocalStorage } from "@uidotdev/usehooks";
import { AnimatePresence, motion } from "framer-motion";
import type { LucideIcon } from "lucide-react";
Expand All @@ -15,6 +14,7 @@ import {
textFadeVariants,
} from "./shell-animations";
import { SIDEBAR_COLLAPSED_KEY } from "./shell-constants";
import { ShellLink, useShellPathname } from "./shell-router-context";
import { Text } from "./shell-text";
import type { TranslationKey } from "./shell-translation-key";

Expand All @@ -26,11 +26,11 @@ interface NavItemProps {

export const NavItem = ({ to, icon: Icon, label }: NavItemProps) => {
const [isCollapsed] = useLocalStorage(SIDEBAR_COLLAPSED_KEY, false);
const { pathname } = useLocation();
const pathname = useShellPathname();
const isActive = pathname === to || pathname.startsWith(`${to}/`);

const linkContent = (
<Link
<ShellLink
to={to}
className={cn(
"flex items-center rounded-md transition-colors duration-200",
Expand Down Expand Up @@ -66,7 +66,7 @@ export const NavItem = ({ to, icon: Icon, label }: NavItemProps) => {
</motion.span>
)}
</AnimatePresence>
</Link>
</ShellLink>
);

if (isCollapsed) {
Expand Down
54 changes: 54 additions & 0 deletions apps/apollo-vertex/registry/shell/shell-router-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
type AnchorHTMLAttributes,
type ComponentType,
createContext,
type PropsWithChildren,
useContext,
} from "react";

export type ShellLinkComponent = ComponentType<{
to: string;
href: string;
className?: string;
children?: React.ReactNode;
}>;

interface ShellLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
to: string;
}

const DefaultLink = ({ to, ...props }: ShellLinkProps) => (
<a href={to} {...props} />
);

interface ShellRouterContextValue {
LinkComponent: ShellLinkComponent;
pathname: string;
}

const ShellRouterContext = createContext<ShellRouterContextValue>({
LinkComponent: DefaultLink,
pathname: "/",
});

export const useShellPathname = () => useContext(ShellRouterContext).pathname;

export const ShellLink = ({ to, href, ...props }: ShellLinkProps) => {
const { LinkComponent } = useContext(ShellRouterContext);
return <LinkComponent to={to} href={href ?? to} {...props} />;
};

interface ShellRouterProviderProps {
linkComponent: ShellLinkComponent;
pathname: string;
}

export const ShellRouterProvider = ({
linkComponent,
pathname,
children,
}: PropsWithChildren<ShellRouterProviderProps>) => (
<ShellRouterContext value={{ LinkComponent: linkComponent, pathname }}>
{children}
</ShellRouterContext>
Comment on lines +51 to +53
);
36 changes: 23 additions & 13 deletions apps/apollo-vertex/registry/shell/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { ShellAuthProvider, useAuth } from "./shell-auth-provider";
import { ShellLayout } from "./shell-layout";
import { LocaleProvider } from "./shell-locale-provider";
import { ShellLogin } from "./shell-login";
import {
type ShellLinkComponent,
ShellRouterProvider,
} from "./shell-router-context";
import type { TranslationKey } from "./shell-translation-key";
import { ShellUserProvider } from "./shell-user-provider";

Expand Down Expand Up @@ -32,6 +36,8 @@ interface ApolloShellProps extends ApolloShellComponentProps {
scope: string;
baseUrl: string;
variant?: "minimal";
linkComponent: ShellLinkComponent;
pathname: string;
}

const ApolloShellComponent: FC<ApolloShellComponentProps> = ({
Expand Down Expand Up @@ -72,20 +78,24 @@ export const ApolloShell: FC<ApolloShellProps> = ({
companyLogo,
variant,
navItems,
linkComponent,
pathname,
}) => {
return (
<ShellAuthProvider clientId={clientId} scope={scope} baseUrl={baseUrl}>
<LocaleProvider>
<ApolloShellComponent
companyName={companyName}
productName={productName}
companyLogo={companyLogo}
variant={variant}
navItems={navItems}
>
{children}
</ApolloShellComponent>
</LocaleProvider>
</ShellAuthProvider>
<ShellRouterProvider linkComponent={linkComponent} pathname={pathname}>
<ShellAuthProvider clientId={clientId} scope={scope} baseUrl={baseUrl}>
<LocaleProvider>
<ApolloShellComponent
companyName={companyName}
productName={productName}
companyLogo={companyLogo}
variant={variant}
navItems={navItems}
>
{children}
</ApolloShellComponent>
</LocaleProvider>
</ShellAuthProvider>
</ShellRouterProvider>
);
};
6 changes: 6 additions & 0 deletions apps/apollo-vertex/templates/ShellTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BarChart3, FolderOpen, Home, Settings, Users } from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import type { PropsWithChildren } from "react";
import type { ShellNavItem } from "@/registry/shell/shell";
import { ApolloShell } from "@/registry/shell/shell";
Expand Down Expand Up @@ -38,6 +40,8 @@ export function ShellTemplate({
variant,
children,
}: PropsWithChildren<ShellTemplateProps>) {
const pathname = usePathname();

return (
<QueryClientProvider client={queryClient}>
<ApolloShell
Expand All @@ -53,6 +57,8 @@ export function ShellTemplate({
scope="openid profile email offline_access"
baseUrl={baseUrl}
navItems={variant === "minimal" ? minimalNavItems : navItems}
linkComponent={Link}
pathname={pathname}
Comment on lines 59 to +61
>
{children}
</ApolloShell>
Expand Down
Loading
Loading