Skip to content
Open
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
4,561 changes: 2,322 additions & 2,239 deletions apps/www/src/app/examples/page.tsx

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions apps/www/src/components/demo/demo-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export default function DemoPreview({
code,
tabs,
scope,
codePreview
codePreview,
previewClassName
}: DemoPreviewProps) {
const [activeTab, setActiveTab] = useState(0);
const [activeCodePreviewTab, setActiveCodePreviewTab] = useState(0);
Expand All @@ -39,8 +40,19 @@ export default function DemoPreview({
))}
</div>
)}
<div className={styles.preview}>
<Preview />
<div
className={cx(
styles.preview,
previewClassName && styles[previewClassName as keyof typeof styles]
)}
>
<Preview
className={
previewClassName === 'previewTop'
? styles.previewContentTop
: undefined
}
/>
</div>

{Array.isArray(codePreview) ? (
Expand Down
33 changes: 33 additions & 0 deletions apps/www/src/components/demo/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,39 @@
border-bottom: 0.5px solid var(--rs-color-border-base-primary);
}

.previewTop {
align-items: flex-start;
justify-content: flex-start;
padding: 0;
min-height: unset;
}

.previewContentTop {
padding: 0 !important;
align-items: flex-start;
justify-content: flex-start;
flex-direction: column;
}

.previewContentTop > * {
margin-bottom: var(--rs-space-8);
}

.previewContentTop::after {
content: "";
display: block;
width: calc(100% - 2 * var(--rs-space-8));
min-height: 200px;
margin: 0 var(--rs-space-8) var(--rs-space-8);
border: 2px dashed var(--rs-color-border-base-secondary);
box-sizing: border-box;
}

/* Hide dashed box for sticky demo - it has its own scrollable box inside */
.previewContentTop:has(> :global(.navbar-sticky-demo-scroll))::after {
display: none;
}

.previewReset {
position: absolute;
bottom: 8px;
Expand Down
1 change: 1 addition & 0 deletions apps/www/src/components/demo/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type DemoPreviewProps = {
tabs?: { name: string; code: string }[];
scope?: ScopeType;
codePreview?: string | TabProps[];
previewClassName?: string;
};

export type DemoPlaygroundProps = {
Expand Down
86 changes: 77 additions & 9 deletions apps/www/src/content/docs/components/navbar/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

export const preview = {
type: 'code',
previewClassName: 'previewTop',
code: `
<Navbar>
<Navbar.Start>
Expand All @@ -21,6 +22,7 @@ export const preview = {

export const stickyDemo = {
type: 'code',
previewClassName: 'previewTop',
tabs: [
{
name: 'Default',
Expand All @@ -39,25 +41,79 @@ export const stickyDemo = {
{
name: 'Sticky',
code: `
<Navbar sticky>
<div className="navbar-sticky-demo-scroll" style={{ width: '100%', alignSelf: 'stretch', overflow: 'auto', height: 300 }}>
<Navbar sticky>
<Navbar.Start>
<Text size="regular" weight="medium">Navigation</Text>
</Navbar.Start>
<Navbar.End>
<Button variant="ghost" size="small">Home</Button>
<Button variant="ghost" size="small">About</Button>
<Button variant="ghost" size="small">Contact</Button>
</Navbar.End>
</Navbar>
<div style={{ margin: 'var(--rs-space-8)', width: 'calc(100% - 2 * var(--rs-space-8))', minHeight: 400, border: '2px dashed var(--rs-color-border-base-secondary)', boxSizing: 'border-box' }} />
</div>`
}
]
};

export const shadowDemo = {
type: 'code',
previewClassName: 'previewTop',
tabs: [
{
name: 'With shadow (default)',
code: `
<Navbar shadow>
<Navbar.Start>
<Text size="regular" weight="medium">Navigation</Text>
<Text size="regular" weight="medium">Brand</Text>
</Navbar.Start>
<Navbar.End>
<Button variant="ghost" size="small">Home</Button>
<Button variant="ghost" size="small">About</Button>
<Button variant="ghost" size="small">Contact</Button>
<Button size="small">Action</Button>
</Navbar.End>
</Navbar>`
},
{
name: 'Without shadow',
code: `
<Navbar shadow={false}>
<Navbar.Start>
<Text size="regular" weight="medium">Brand</Text>
</Navbar.Start>
<Navbar.End>
<Button size="small">Action</Button>
</Navbar.End>
</Navbar>`
}
]
};

export const hideOnScrollDemo = {
type: 'code',
previewClassName: 'previewTop',
code: `
<div className="navbar-sticky-demo-scroll" style={{ width: '100%', alignSelf: 'stretch', overflow: 'auto', height: 300 }}>
<Navbar sticky hideOnScroll>
<Navbar.Start>
<Text size="regular" weight="medium">Navigation</Text>
</Navbar.Start>
<Navbar.End>
<Button variant="ghost" size="small">Home</Button>
<Button variant="ghost" size="small">About</Button>
<Button variant="ghost" size="small">Contact</Button>
</Navbar.End>
</Navbar>
<div style={{ margin: 'var(--rs-space-8)', width: 'calc(100% - 2 * var(--rs-space-8))', minHeight: 400, border: '2px dashed var(--rs-color-border-base-secondary)', boxSizing: 'border-box' }} />
</div>`
};

export const sectionsDemo = {
type: 'code',
previewClassName: 'previewTop',
tabs: [
{
name: 'Start Only',
name: 'Start',
code: `
<Navbar>
<Navbar.Start>
Expand All @@ -66,7 +122,16 @@ export const sectionsDemo = {
</Navbar>`
},
{
name: 'End Only',
name: 'Center',
code: `
<Navbar>
<Navbar.Center>
<Text size="regular" weight="medium">Centered Title</Text>
</Navbar.Center>
</Navbar>`
},
{
name: 'End',
code: `
<Navbar>
<Navbar.End>
Expand All @@ -76,14 +141,16 @@ export const sectionsDemo = {
</Navbar>`
},
{
name: 'Both Sections',
name: 'Start, Center and End',
code: `
<Navbar>
<Navbar.Start>
<Text size="regular" weight="medium">Explore</Text>
</Navbar.Start>
<Navbar.Center>
<Text size="regular" weight="medium">Brand</Text>
</Navbar.Center>
<Navbar.End>
<Search placeholder="Search..." size="small" style={{ width: '200px' }} />
<Button variant="outline" size="small">Action</Button>
</Navbar.End>
</Navbar>`
Expand All @@ -93,6 +160,7 @@ export const sectionsDemo = {

export const accessibilityDemo = {
type: 'code',
previewClassName: 'previewTop',
tabs: [
{
name: 'Custom aria-label',
Expand Down
31 changes: 26 additions & 5 deletions apps/www/src/content/docs/components/navbar/index.mdx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
---
title: Navbar
description: A horizontal navigation bar component with flexible left and right sections for building site headers and navigation.
description: A horizontal navigation bar component with flexible start, center, and end sections for building site headers and navigation.
source: packages/raystack/components/navbar
tag: new
---

import {
preview,
stickyDemo,
shadowDemo,
sectionsDemo,
hideOnScrollDemo,
accessibilityDemo,
} from "./demo.ts";

Expand All @@ -23,6 +25,7 @@ import { Navbar } from "@raystack/apsara";

<Navbar>
<Navbar.Start />
<Navbar.Center />
<Navbar.End />
</Navbar>
```
Expand All @@ -37,13 +40,19 @@ Renders the navigation bar container.

### Start

The start section is a container component that accepts all `div` props. It's commonly used for brand logos, primary navigation links, or page titles.
The start section is a container that accepts Flex props (`align`, `gap`, `direction`, etc.) and section props. It's commonly used for brand logos, primary navigation links, or page titles.

<auto-type-table path="./props.ts" name="NavbarStartProps" />

### Center

The center section sits in the middle of the navbar in a fixed position—it stays absolutely centered regardless of the width of Start or End content. The navbar uses a 3-column grid (Start | Center | End) so the center does not shift when left or right content changes. It accepts Flex props and section props.

<auto-type-table path="./props.ts" name="NavbarCenterProps" />

### End

The end section is a container component that accepts all `div` props. It's commonly used for search inputs, action buttons, user menus, or secondary navigation.
The end section is a container that accepts Flex props and section props. It's commonly used for search inputs, action buttons, user menus, or secondary navigation.

<auto-type-table path="./props.ts" name="NavbarEndProps" />

Expand All @@ -55,12 +64,24 @@ The Navbar can be made sticky to remain visible at the top of the viewport when

<Demo data={stickyDemo} />

### Shadow

Use the `shadow` prop to show or hide the bottom shadow. Default is `true`.

<Demo data={shadowDemo} />

### Section Layouts

You can use either or both sections depending on your needs. The sections automatically position themselves with proper spacing.
You can use any combination of Start, Center, and End. The navbar uses a 3-column grid so each section renders in its own space; the center remains absolutely centered.

<Demo data={sectionsDemo} />

### Hide on scroll

Set `hideOnScroll` to hide the navbar when the user scrolls down and show it when they scroll up. It works with both window scroll and scroll containers (e.g. ScrollArea). The navbar slides out of view with a transition. The slide animation is only visible when the navbar is sticky (or fixed); without it, the navbar simply scrolls away with the content.

<Demo data={hideOnScrollDemo} />

### Accessibility

The Navbar supports custom ARIA labels for better screen reader support. You can provide descriptive labels for the entire navbar or individual sections.
Expand All @@ -73,7 +94,7 @@ The Navbar implements the following accessibility features:

- Proper ARIA roles and attributes
- `role="navigation"` for the main navbar
- `role="group"` for Start and End sections when `aria-label` is provided
- `role="group"` for Start, Center, and End sections when `aria-label` is provided
- Customizable `aria-label` and `aria-labelledby` support

- Semantic HTML
Expand Down
20 changes: 20 additions & 0 deletions apps/www/src/content/docs/components/navbar/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ export interface NavbarRootProps {
*/
sticky?: boolean;

/**
* Show the bottom shadow.
* @default true
*/
shadow?: boolean;

/**
* Hide the navbar when the user scrolls down, show it when they scroll up.
* Uses the navbar's scroll parent (e.g. ScrollArea) or window.
* @default false
*/
hideOnScroll?: boolean;

/**
* Accessible label for the navigation.
* Use this to provide a description of the navbar's purpose.
Expand All @@ -27,6 +40,13 @@ export interface NavbarStartProps {
'aria-label'?: string;
}

export interface NavbarCenterProps {
/**
* Accessible label for the center section. When provided, the section will have `role="group"`.
*/
'aria-label'?: string;
}

export interface NavbarEndProps {
/**
* Accessible label for the end section. Use this to describe the purpose
Expand Down
Loading