# 侧边导航

## 使用方法

`SideNav` 是页面一侧的导航地标。里面按 `SideNavSection`、`SideNavHeading`、`SideNavItem` 组织。`collapsible` 打开后，栏可以收成只剩图标的窄条，`SideNavCollapseButton` 在侧栏顶部靠右。收起后，没有图标的项不会渲染；有下级的项改成从侧面弹出的菜单。`SideNavItem` 的 `actions` 插槽和主控件并排，不放进链接里面，侧栏收起后不再渲染。

用 `v-model:is-collapsed` 受控。`collapsible` 也可以传对象，关掉内置按钮，或给一个快捷键，例如 `mod+\\`。`resizable` 打开后，结束边上可以拖宽度，默认从 260px 起，范围是 180px 到 480px。收起后把手会藏起来。拖到 160px 以下、并且侧栏可以收起时，栏会收成图标条。

```vue
<script setup lang="ts">
import { SideNav, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
import { ref } from 'vue'

const collapsed = ref(false)
</script>

<template>
  <SideNav v-model:is-collapsed="collapsed" collapsible>
    <SideNavSection title="工作区">
      <SideNavItem href="/home" icon-class="i-carbon-home" label="首页" />
    </SideNavSection>
  </SideNav>
</template>
```

### 结构

- **产品图标和名称**: 导航顶部的品牌区。
- **导航项**: 可导航链接的分区和分组。
- **收起和展开开关**: 收起或展开侧边导航的开关。

## 最佳实践

| 指引 | 实践 |
| --- | --- |
| 推荐 | 会收起的项都带图标，否则收起后这一项会消失。 |
| 推荐 | 一项既要跳转又有下级时写上 `href`。点文字跳转，点箭头才收起。 |
| 推荐 | 需要用户自己调栏宽时打开 `resizable`。收起状态仍用 `v-model:is-collapsed`，不要在 `collapsible` 和 `resizable` 里各写一套。 |

## 示例

### 尾部内容

每一行末尾可以是菜单、数量、徽章或辅助文字。

```vue
<script setup lang="ts">
import { Badge } from '@astryx-vue/core/Badge'
import { MoreMenu } from '@astryx-vue/core/MoreMenu'
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
import { Text } from '@astryx-vue/core/Text'
</script>

<template>
  <div class="side-nav-preview">
    <SideNav>
      <template #header>
        <SideNavHeading heading="My App" heading-href="#home" />
      </template>
      <SideNavSection title="Navigation" is-header-hidden>
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard">
          <template #end>
            <MoreMenu
              label="Dashboard actions"
              size="sm"
              :items="[{ label: 'Pin to top' }, { label: 'Rename' }]"
            />
          </template>
        </SideNavItem>
        <SideNavItem href="#projects" icon-class="i-carbon-folder" label="Projects">
          <template #end>
            <Badge>12</Badge>
          </template>
        </SideNavItem>
        <SideNavItem href="#analytics" icon-class="i-carbon-analytics" label="Analytics">
          <template #end>
            <Badge>New</Badge>
          </template>
        </SideNavItem>
        <SideNavItem href="#team" icon-class="i-carbon-group" label="Team">
          <template #end>
            <Text color="secondary" type="supporting">
              8 members
            </Text>
          </template>
        </SideNavItem>
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

### 嵌套项

设置项展开后是一组可以折叠的子项。

```vue
<script setup lang="ts">
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
</script>

<template>
  <div class="side-nav-preview">
    <SideNav>
      <template #header>
        <SideNavHeading heading="My App" />
      </template>
      <SideNavSection title="Main">
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
        <SideNavItem icon-class="i-carbon-settings" label="Settings">
          <SideNavItem href="#settings-general" label="General" />
          <SideNavItem href="#settings-security" label="Security" />
          <SideNavItem href="#settings-notifications" label="Notifications" />
        </SideNavItem>
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

### 带菜单的标题

标题是账户切换器，显示产品名和当前账户。

```vue
<script setup lang="ts">
import { NavIcon } from '@astryx-vue/core/NavItem'
import { NavHeadingMenu, NavHeadingMenuItem } from '@astryx-vue/core/NavMenu'
import { SideNav, SideNavHeading, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
</script>

<template>
  <div class="side-nav-preview">
    <SideNav>
      <template #header>
        <SideNavHeading heading="Product Name" subheading="Business Account">
          <template #icon>
            <NavIcon icon-class="i-carbon-cube" label="Product" />
          </template>
          <template #menu>
            <NavHeadingMenu label="Accounts">
              <NavHeadingMenuItem href="#personal" label="Personal Account" />
              <NavHeadingMenuItem href="#acme" label="Acme Corp" />
              <NavHeadingMenuItem href="#add" label="Add account" />
              <NavHeadingMenuItem href="#sign-out" label="Sign out" />
            </NavHeadingMenu>
          </template>
        </SideNavHeading>
      </template>
      <SideNavSection title="Navigation">
        <SideNavItem href="#dashboard" icon-class="i-carbon-home" is-selected label="Dashboard" />
        <SideNavItem href="#settings" icon-class="i-carbon-settings" label="Settings" />
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

### 拖拽宽度

拖结束边上的把手改变栏宽。拖得很窄时侧栏会收起，把手随之隐藏。

```vue
<script setup lang="ts">
import { SideNav, SideNavItem, SideNavSection } from '@astryx-vue/core/SideNav'
</script>

<template>
  <div class="side-nav-preview" style="width: min(100%, 32rem); height: 280px">
    <SideNav collapsible resizable>
      <SideNavSection title="Library">
        <SideNavItem href="#home" icon-class="i-carbon-home" is-selected label="Home" />
        <SideNavItem href="#files" icon-class="i-carbon-folder" label="Files" />
        <SideNavItem href="#mail" icon-class="i-carbon-email" label="Mail" />
      </SideNavSection>
    </SideNav>
  </div>
</template>
```

## SideNav Props

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `label` | `string` | 当前语言的「侧边导航」 | 导航地标的无障碍名称。 |
| `collapsible` | `boolean \| SideNavCollapsible` | `false` | 允许收成图标栏。对象可设置初始状态、内置按钮和快捷键。 |
| `isCollapsed` | `boolean` | - | 受控收起状态，配合 `v-model:is-collapsed`。 |
| `resizable` | `boolean \| SideNavResizable` | `false` | 在结束边拖宽度。对象可设置初始宽度、最小和最大宽度，以及记住宽度的 `autoSaveId`。 |
| `handleRef` | `HandleRef` | - | 侧栏外面的按钮可以拿到收起、展开和切换。更常见的做法是两边共用 `v-model:is-collapsed`。 |

## SideNav 事件

| 名称 | 说明 |
| --- | --- |
| `update:isCollapsed` | 收起状态变化，用于 `v-model:is-collapsed`。 |
| `collapsedChange` | 收起状态变化时触发。 |
| `widthChange` | 拖拽改变宽度时触发，参数是像素宽度。 |

## SideNav Slots

| 名称 | 说明 |
| --- | --- |
| `default` | 导航主体，通常放分组和导航项。 |
| `header` | 顶部品牌区。 |
| `top` | 品牌区下面的附加内容。 |
| `footer` | 底部内容，位于收起按钮之上。 |
| `footerIcons` | 和收起按钮同一行的图标。 |

## SideNavSection Props

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `title` | `string` | - | 分组标题。收起后仍留给读屏。 |
| `subtitle` | `string` | - | 标题下面的辅助文字。 |
| `isHeaderHidden` | `boolean` | `false` | 视觉上隐藏标题，读屏仍能读到。 |

## SideNavItem Props

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `label` | `string` | - | 项的名称。 |
| `href` | `string` | - | 跳转地址。有下级时，点文字跳转，点箭头收起。 |
| `as` | `NavLinkComponent` | `'a'` | 链接根组件。 |
| `iconClass` | `string` | - | 图标 CSS class。收起后没有图标的项不渲染。 |
| `isSelected` | `boolean` | `false` | 当前页。 |
| `isDisabled` | `boolean` | `false` | 禁用。 |
| `collapsible` | `boolean \| object` | - | 有下级时是否可收起。传 `false` 则下级一直展开。 |

## SideNavItem Slots

| 名称 | 说明 |
| --- | --- |
| `default` | 下级项。 |
| `icon` | 项前面的图标。 |
| `selectedIcon` | 选中时替换默认图标。 |
| `end` | 主控件末尾的内容，仍在链接或按钮里面。 |
| `actions` | 和主控件并排的操作，例如图标按钮。不放进链接里面。侧栏收起后不渲染。 |

## SideNavHeading Props

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `heading` | `string` | - | 产品或应用名称。 |
| `headingHref` | `string` | - | 主标题链接。 |
| `superheading` | `string` | - | 主标题上方的小字。 |
| `superheadingHref` | `string` | - | 上方小字的链接。 |
| `subheading` | `string` | - | 主标题下方的小字。 |
| `subheadingHref` | `string` | - | 下方小字的链接。 |
| `logoLabel` | `string` | - | 标志单独成链接时的无障碍名称。不传则用 `heading`。 |
| `as` | `NavLinkComponent` | `'a'` | 链接根组件。 |

## SideNavHeading Slots

| 名称 | 说明 |
| --- | --- |
| `icon` | 标题前的标志。收起后只剩这一块。 |
| `end` | 标题行末尾。 |
| `menu` | 弹出菜单，通常放 `NavHeadingMenu`。作用域提供 `close` 和 `focusRequest`。 |

## SideNavCollapseButton Props

在展开和收起的侧栏之间切换。放在 `SideNav` 里时从侧栏读折叠状态；放在外面时用 `v-model:is-collapsed` 或 `collapsible` 绑同一个状态。

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `label` | `string` | - | 按钮文字。给了文字就渲染成「箭头 + 文字」的按钮；不给则只有箭头图标，无障碍名称用翻译好的「收起侧边栏 / 展开侧边栏」。 |
| `collapsible` | `SideNavControlledCollapsible` | - | 受控的 `{ isCollapsed, onCollapsedChange }` 配置，给放在侧栏外面的按钮用。把同一个对象也交给 `SideNav`。它优先于 `isCollapsed`。 |
| `isCollapsed` | `boolean` | - | 折叠状态，用于 `v-model:is-collapsed`。按钮不在侧栏里时用它和侧栏连到同一个状态。 |
| `size` | `'sm' \| 'md' \| 'lg'` | 在 SideNav 里是 `sm`，外面是 `md` | 按钮尺寸。按钮放在有尺寸的容器外面、又要和旁边对齐时指定。 |

## SideNavCollapseButton 插槽

| 名称 | 说明 |
| --- | --- |
| `default` | 自定义按钮图标插槽的内容，替换默认的箭头。看得见的文字仍然来自 `label`。 |
