npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tauri-app-shell

v0.2.0

Published

Transparent custom titlebar + flexible multi-column layout shell for Tauri 2.0 + React

Readme

tauri-app-shell

Tauri 2.0 + React 透明自定义标题栏 + 弹性多列布局组件。

  • 透明窗口,标题栏颜色与下方内容列自然连续
  • macOS 保留原生红绿灯,Windows / Linux 自绘窗口控制按钮
  • 支持单栏 / 两栏 / 三栏,侧边栏和右侧面板均可折叠、可拖拽调整宽度
  • 支持侧边栏拖拽吸附:就近吸附、阈值吸附、方向吸附三种模式
  • 底部面板(Bottom Panel):可拖拽调整高度,支持 wide/center 两种布局模式
  • 状态栏(Status Bar):固定高度信息展示栏,支持 full/workbench 两种布局模式
  • 所有标题栏区域均为插槽,完全自定义
  • 内置浅色 / 深色主题,支持跟随系统或手动切换

安装

pnpm add tauri-app-shell

或使用 npm:

npm install tauri-app-shell

锁定版本(推荐生产环境):

pnpm add tauri-app-shell@<version>

<version> 替换为你要使用的发布版本。


Tauri 侧配置(必须)

1. 基础窗口配置

src-tauri/tauri.conf.json

{
  "app": {
    "windows": [{
      "title": "app",
      "width": 1200,
      "height": 800,
      "center": true,
      "minWidth": 600,
      "minHeight": 400
    }]
  }
}

将公共配置保留在基础文件里,把透明窗口、标题栏样式等平台差异放到各平台配置文件中。

2. 平台配置文件

**src-tauri/tauri.macos.conf.json**

{
  "app": {
    "windows": [{
      "titleBarStyle": "Overlay",
      "hiddenTitle": true,
      "transparent": true,
      "trafficLightPosition": { "x": 14, "y": 16 }
    }]
  }
}

**src-tauri/tauri.windows.conf.json**

{
  "app": {
    "windows": [{ "decorations": false, "transparent": true }]
  }
}

**src-tauri/tauri.linux.conf.json**

{
  "app": {
    "windows": [{ "decorations": false, "transparent": false }]
  }
}

Tauri 不会自动发现这些平台配置文件。请在 package.json 里显式传入 --config

{
  "scripts": {
    "tauri:dev:mac": "tauri dev --config src-tauri/tauri.macos.conf.json",
    "tauri:dev:win": "tauri dev --config src-tauri/tauri.windows.conf.json",
    "tauri:dev:linux": "tauri dev --config src-tauri/tauri.linux.conf.json"
  }
}

3. 开启拖拽权限

**src-tauri/capabilities/default.json**

{
  "permissions": [
    "core:default",
    "core:window:allow-start-dragging"
  ]
}

重要约束

AppShell 必须作为应用的最外层根组件直接渲染,外层不允许再包裹任何其他组件或 DOM 元素。

// ✅ 正确
export default function App() {
  return (
    <AppShell>
      ...
    </AppShell>
  );
}

// ❌ 错误 —— AppShell 外层有包裹元素
export default function App() {
  return (
    <div className="wrapper">
      <AppShell>
        ...
      </AppShell>
    </div>
  );
}

外层包裹元素会破坏 width: 100% / height: 100% 的铺满逻辑,导致白边、布局错位或透明窗口失效。


使用

1. 全局基础样式(必须)

在全局 CSS 文件(如 src/index.css)中添加,确保组件能铺满整个透明窗口:

html, body, #root {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background: transparent;
}

缺少这段样式会导致窗口无法铺满、出现白边或滚动条。

2. 引入组件样式(只需一次)

在入口文件(如 src/main.tsx)中引入:

import 'tauri-app-shell/style';

Demo

单栏

import { AppShell } from 'tauri-app-shell';

export default function App() {
  return (
    <AppShell>
      <div>主内容</div>
    </AppShell>
  );
}

两栏(左侧边栏 + 主内容)

import { AppShell } from 'tauri-app-shell';

export default function App() {
  return (
    <AppShell sidebar={<Sidebar />}>
      <main>主内容</main>
    </AppShell>
  );
}

三栏

import { AppShell } from 'tauri-app-shell';

export default function App() {
  return (
    <AppShell
      sidebar={<LeftSidebar />}
      rightPanel={<RightPanel />}
    >
      <main>主内容</main>
    </AppShell>
  );
}

自定义标题栏内容

<AppShell
  sidebar={<Sidebar />}
  titlebarCenter={<span>My App</span>}
  titlebarRight={<SearchButton />}
>
  <main>主内容</main>
</AppShell>

隐藏折叠按钮

// 不显示侧边栏折叠按钮
<AppShell sidebar={<Sidebar />} sidebarToggle={false}>
  <main>主内容</main>
</AppShell>

替换折叠按钮为自定义内容

<AppShell
  sidebar={<Sidebar />}
  sidebarToggle={<button onClick={...}><MyIcon /></button>}
>
  <main>主内容</main>
</AppShell>

红绿灯右侧放自定义按钮(无折叠按钮)

<AppShell
  sidebarToggle={false}
  titlebarLeft={
    <>
      <BackButton />
      <NewButton />
    </>
  }
>
  <main>主内容</main>
</AppShell>

侧边栏宽度吸附

默认拖拽是连续宽度。传入 sidebarSnapPoints 后,侧边栏会在拖拽过程中或拖拽结束时吸附到指定宽度。

就近吸附(nearest,默认)

拖拽结束时吸附到距离当前位置最近的宽度点,适合一般工具面板。

<AppShell
  sidebar={<Sidebar />}
  defaultSidebarWidth={200}
  sidebarMinWidth={80}
  sidebarMaxWidth={200}
  sidebarSnapPoints={[80, 200]}
  sidebarSnapMode="nearest"
>
  <main>主内容</main>
</AppShell>

阈值吸附(threshold)

拖拽结束时按阈值判断。以下示例中,<= 80 吸到 80> 80 吸到 200

<AppShell
  sidebar={<Sidebar />}
  defaultSidebarWidth={200}
  sidebarMinWidth={80}
  sidebarMaxWidth={200}
  sidebarSnapPoints={[80, 200]}
  sidebarSnapMode="threshold"
  sidebarSnapThreshold={80}
>
  <main>主内容</main>
</AppShell>

方向吸附(direction)

拖拽过程中立即按方向切换:向右拖吸到最大点,向左拖吸到最小点。适合企业微信式“窄栏 / 展开栏”两态导航。

<AppShell
  sidebar={<Sidebar />}
  defaultSidebarWidth={200}
  sidebarMinWidth={80}
  sidebarMaxWidth={200}
  sidebarSnapPoints={[80, 200]}
  sidebarSnapMode="direction"
>
  <main>主内容</main>
</AppShell>

底部面板(Bottom Panel)

可拖拽调整高度的富内容面板(终端、日志、输出等)。

wide 模式(默认)—— 面板横跨 Main + RightPanel

<AppShell
  sidebar={<FileTree />}
  rightPanel={<AICopilot />}
  bottomPanel={<Terminal />}
>
  <EditorArea />
</AppShell>

center 模式 —— 面板仅在 Main 下方,RightPanel 全高

<AppShell
  sidebar={<FileTree />}
  rightPanel={<AICopilot />}
  bottomPanel={<Terminal />}
  bottomPanelLayout="center"
>
  <EditorArea />
</AppShell>

受控模式

const [panelOpen, setPanelOpen] = useState(false);

<AppShell
  bottomPanel={<CommandOutput />}
  bottomPanelOpen={panelOpen}
  onBottomPanelOpenChange={setPanelOpen}
  bottomPanelToggle={false}
  defaultBottomPanelHeight={160}
>
  <Canvas />
</AppShell>

状态栏(Status Bar)

固定 24px 的信息展示栏。

full 模式(默认)—— 横跨窗口 100% 宽度

<AppShell
  sidebar={<Nav />}
  statusBar={
    <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
      <div>git: main</div>
      <div>Ln 42, Col 8</div>
    </div>
  }
>
  <Editor />
</AppShell>

workbench 模式 —— 仅覆盖 Main + RightPanel,Sidebar 全高

<AppShell
  sidebar={<FileTree />}
  rightPanel={<AICopilot />}
  statusBarLayout="workbench"
  statusBar={<StatusInfo />}
>
  <Canvas />
</AppShell>

Props

| Prop | 类型 | 默认值 | 说明 | | ------------------------ | ------------------- | ----------- | ----------------------------------------------- | | children | ReactNode | 必填 | 主内容区 | | sidebar | ReactNode | — | 左侧边栏;不传则不渲染 | | rightPanel | ReactNode | — | 右侧面板;不传则不渲染 | | bottomPanel | ReactNode | — | 底部面板;不传则不渲染 | | statusBar | ReactNode | — | 状态栏;不传则不渲染 | | sidebarToggle | ReactNode \| false | undefined | undefined 有 sidebar 时显示默认按钮;false 隐藏;传节点则替换 | | rightPanelToggle | ReactNode \| false | undefined | 同上,控制右侧面板切换按钮 | | bottomPanelToggle | ReactNode \| false | undefined | 同上,控制底部面板切换按钮 | | titlebarLeft | ReactNode | — | 标题栏左侧额外内容(sidebarToggle 之后) | | titlebarCenter | ReactNode | — | 标题栏中间(可拖拽区域内) | | titlebarRight | ReactNode | — | 标题栏右侧额外内容(rightPanelToggle 之前) | | defaultSidebarOpen | boolean | true | 侧边栏初始展开状态 | | rightPanelOpen | boolean | — | 受控:右侧面板展开状态;传入后由调用方管理 | | defaultRightPanelOpen | boolean | true | 非受控:右侧面板初始展开状态 | | onRightPanelOpenChange | (open: boolean) => void | — | 右侧面板开关变化时的回调 | | bottomPanelOpen | boolean | — | 受控:底部面板展开状态;传入后由调用方管理 | | defaultBottomPanelOpen | boolean | true | 非受控:底部面板初始展开状态 | | onBottomPanelOpenChange | (open: boolean) => void | — | 底部面板开关变化时的回调 | | defaultSidebarWidth | number | 220 | 侧边栏初始宽度(px) | | sidebarMinWidth | number | 140 | 侧边栏拖拽最小宽度(px) | | sidebarMaxWidth | number | 480 | 侧边栏拖拽最大宽度(px) | | sidebarSnapPoints | readonly number[] | — | 侧边栏吸附宽度点;不传则保持连续拖拽 | | sidebarSnapMode | 'nearest' \| 'threshold' \| 'direction' | 'nearest' | 吸附模式:就近、阈值、方向 | | sidebarSnapThreshold | number | 最小吸附点 | threshold 模式阈值;<= 阈值吸到最小点,否则吸到最大点 | | defaultRightPanelWidth | number | 260 | 右侧面板初始宽度(px) | | rightPanelMinWidth | number | 160 | 右侧面板拖拽最小宽度(px) | | rightPanelMaxWidth | number | 520 | 右侧面板拖拽最大宽度(px) | | defaultBottomPanelHeight | number | 200 | 底部面板初始高度(px) | | bottomPanelMinHeight | number | 100 | 底部面板拖拽最小高度(px) | | bottomPanelMaxHeight | number | 600 | 底部面板拖拽最大高度(px) | | bottomPanelLayout | 'wide' \| 'center' | 'wide' | 底部面板布局:wide 横跨 Main+RightPanel;center 仅 Main 下方 | | statusBarLayout | 'full' \| 'workbench' | 'full' | 状态栏布局:full 横跨窗口;workbench 仅 Main+RightPanel |


主题切换

默认跟随系统 prefers-color-scheme。如需手动切换,在 <html> 上设置 data-theme

document.documentElement.setAttribute('data-theme', 'dark');
document.documentElement.setAttribute('data-theme', 'light');
document.documentElement.removeAttribute('data-theme');

React 中可以这样写:

useEffect(() => {
  document.documentElement.setAttribute('data-theme', theme);
  return () => document.documentElement.removeAttribute('data-theme');
}, [theme]);

CSS 变量定制

.app-shell 父元素上覆盖变量即可调整主题:

.app-shell {
  --shell-sidebar-width:      220px;    /* 侧边栏宽度(拖拽时自动更新) */
  --shell-right-panel-width:  260px;    /* 右面板宽度(拖拽时自动更新) */
  --shell-titlebar-height:    36px;     /* 标题栏高度 */
  --shell-traffic-spacer-w:   74px;     /* macOS 红绿灯占位宽,跟随 trafficLightPosition.x */
  --shell-sidebar-bg:         #f3f3f3;  /* 侧边栏背景色 */
  --shell-sidebar-color:      #3a3c3e;  /* 侧边栏文字色 */
  --shell-main-bg:            #ffffff;  /* 主内容区 / 右面板背景色 */
  --shell-main-color:         #1a1a1a;  /* 主内容区 / 右面板文字色 */
  --shell-border-color:       rgba(0, 0, 0, 0.07); /* 分隔线颜色 */
  --shell-icon-color:         #3a3a3a;  /* 标题栏图标色 */
  --shell-icon-hover-bg:      rgba(0, 0, 0, 0.10); /* 图标悬停背景 */
  --shell-transition:         0.22s ease;
  /* 底部面板 / 状态栏 */
  --shell-bottom-panel-height: 200px;   /* 底部面板高度(拖拽时自动更新) */
  --shell-bottom-panel-bg:    #ffffff;  /* 底部面板背景色 */
  --shell-bottom-panel-color: #1a1a1a;  /* 底部面板文字色 */
  --shell-statusbar-height:   24px;     /* 状态栏高度 */
  --shell-statusbar-bg:       #f3f3f3;  /* 状态栏背景色 */
  --shell-statusbar-color:    #5a5a5a;  /* 状态栏文字色 */
  --shell-statusbar-border-color: rgba(0, 0, 0, 0.08); /* 状态栏上边框色 */
  /* 默认无圆角/阴影(适合 Tauri 全屏窗口);需要浮动卡片效果时启用: */
  /* --shell-radius: 12px; */
  /* --shell-shadow: 0 20px 60px rgba(0, 0, 0, 0.25); */
}

发版(维护者)

使用内置发版脚本,自动完成:更新 package.json 版本号 → 构建 → commit → 打 Tag → 推送 Git → 发布到 npm。

# 格式:pnpm release <版本号>
pnpm release <version>

脚本会自动校验:

  • 版本号格式是否正确(x.y.z)
  • 工作区是否有未提交的改动
  • Tag 是否已存在

发版成功后,其他项目执行以下命令升级:

pnpm add tauri-app-shell@<version>

注意:首次发布前请确保已登录 npm(npm login)。


peerDependencies

| 包 | 版本 | | ----------------- | ----------- | | react | >=18 | | react-dom | >=18 | | @tauri-apps/api | >=2 | | lucide-react | >=0.300.0 |