10 KiB
Hide Layout Chrome for common Role Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Conditionally hide sidebar, navbar, tags-view, and the floating Settings button — and stretch <app-main /> to fill the viewport — when the logged-in user's role list contains "common".
Architecture: Add a single isCommonUser computed to src/layout/index.vue that derives from the existing Pinia useUserStore. Use that computed as a v-if gate on every chrome element and as a class binding on .main-container. Add one scoped SCSS rule for the fullscreen layout. No new files, no store/router/permission changes.
Tech Stack: Vue 3 (Composition API, <script setup>), Pinia, Vue Router, Element Plus, SCSS, Vuex-pattern Vue project (this is the vue-element-plus-admin template family).
Spec: docs/superpowers/specs/2026-08-04-hide-chrome-for-common-role-design.md
File Structure
Only one file changes:
| File | Change | Responsibility |
|---|---|---|
src/layout/index.vue |
Edit (script + template + style) | Add isCommonUser computed, gate chrome with v-if, add fullscreen class binding, add fullscreen SCSS rule |
No new files. No test files (the project has no frontend test infrastructure — see spec § Testing; verification is manual).
Task 1: Apply all src/layout/index.vue edits
Files:
- Modify:
src/layout/index.vue:1-115(entire file)
This task is one edit cycle but split into named sub-steps so the implementer can verify the diff top-to-bottom. Use the Edit tool with exact string matching against the current file.
Step 1.1 — Add useUserStore import
In <script setup>, the current line is:
import useSettingsStore from '@/store/modules/settings'
const theme = computed(() => settingsStore.theme)
It must become:
import useSettingsStore from '@/store/modules/settings'
import useUserStore from '@/store/modules/user'
const isCommonUser = computed(() =>
useUserStore().roles?.includes('common') ?? false
)
Edit (exact old → new):
old:
import useSettingsStore from '@/store/modules/settings'
new:
import useSettingsStore from '@/store/modules/settings'
import useUserStore from '@/store/modules/user'
const isCommonUser = computed(() =>
useUserStore().roles?.includes('common') ?? false
)
Step 1.2 — Gate the four chrome elements + add fullscreen class
Current template body (lines 1-14):
<template>
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33' }">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<navbar @setLayout="setLayout" />
<tags-view v-if="needTagsView" />
</div>
<app-main />
<settings ref="settingRef" />
</div>
</div>
</template>
Must become:
<template>
<div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33' }">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar v-if="!sidebar.hide && !isCommonUser" class="sidebar-container" />
<div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide, fullscreen: isCommonUser }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<navbar v-if="!isCommonUser" @setLayout="setLayout" />
<tags-view v-if="needTagsView && !isCommonUser" />
</div>
<app-main />
<settings v-if="!isCommonUser" ref="settingRef" />
</div>
</div>
</template>
Five edits inside the template — do them one at a time with Edit if needed, or use Edit replace_all=false on each line above (each old/new pair is unique enough).
Edit 1 — sidebar line:
- <sidebar v-if="!sidebar.hide" class="sidebar-container" />
+ <sidebar v-if="!sidebar.hide && !isCommonUser" class="sidebar-container" />
Edit 2 — main-container opening line:
- <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
+ <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide, fullscreen: isCommonUser }" class="main-container">
Edit 3 — navbar line:
- <navbar @setLayout="setLayout" />
+ <navbar v-if="!isCommonUser" @setLayout="setLayout" />
Edit 4 — tags-view line:
- <tags-view v-if="needTagsView" />
+ <tags-view v-if="needTagsView && !isCommonUser" />
Edit 5 — settings line:
- <settings ref="settingRef" />
+ <settings v-if="!isCommonUser" ref="settingRef" />
Step 1.3 — Add .fullscreen SCSS rule
Inside the existing <style lang="scss" scoped> block, append after the .mobile .fixed-header rule at line ~115:
.main-container.fullscreen {
position: absolute;
inset: 0;
width: 100% !important;
height: 100% !important;
margin-left: 0 !important;
}
Use Edit with surrounding context to make the match unique — for example, anchor on .mobile .fixed-header block ending with width: 100%; followed by }.
Step 1.4 — Self-check the diff
Re-read the whole file (src/layout/index.vue) and confirm:
-
useUserStoreimport is present andisCommonUsercomputed is declared in<script setup>. -
<sidebar>,<navbar>,<tags-view>,<settings>all carryv-ifgating on!isCommonUser. -
The
<div class="main-container">hasfullscreen: isCommonUserin its class binding. -
.main-container.fullscreenSCSS rule is inside the scoped<style>block. -
Step 1 completed
Task 2: Manual verification
The project has no automated test suite (package.json scripts only include dev and build). Verify by running the dev server and exercising both role paths.
Step 2.1 — Start the dev server
Run (from D:/数科智联/agent-web/agent-web):
yarn dev
Expected: Vite/Element-Plus dev server starts; URL is logged (typically http://localhost:5173 or similar). Leave running.
Step 2.2 — Verify admin role (no common in roles)
- Open the dev URL in a browser.
- Log in as a user whose
rolesarray does not include"common"(e.g. admin / editor test accounts). - Open browser DevTools → Vue DevTools (or just inspect the DOM). Confirm all four are present in
#app:<aside>containing the left sidebar.- Top
<header>/ navbar. - Tags-view row beneath the navbar.
<app-main />to the right.
- Confirm the floating Settings button is visible at the bottom-right.
- Click a couple of navigation links; tags-view and sidebar behavior should be unchanged from prior baseline.
Expected: identical to pre-change behavior. If anything looks off (extra padding, missing element), stop and re-read the file diff.
Step 2.3 — Verify common role (chromeless)
- Log out, then log in as a user whose
rolesarray contains"common"(e.g.['common']or['common', 'something-else']). - Reload the page if needed.
- Confirm visually:
- No left sidebar.
- No top navbar.
- No tags-view row.
- No Settings floating button.
<app-main />fills the entire viewport edge-to-edge (no sidebar gutter, no top whitespace from where navbar was).
- Resize the window narrower to test responsive:
.fullscreenshould remain full screen at all widths. - Inside
<app-main />, exercise the page's own controls (links, buttons, forms) to confirm interaction still works.
Expected: clean chromeless experience. If you see a gap or scrollbar that wasn't there before, the SCSS rule did not apply — check that the class binding in the template is correct and that <style scoped> did not strip the selector (use :deep if necessary, though for a scoped class on a top-level element this should not be needed).
Step 2.4 — Verify mixed role ['admin', 'common']
Repeat Step 2.3 with a user whose roles list is ['admin', 'common']. Because Array.prototype.includes semantics treat any inclusion as "match", chrome should be hidden. If you see chrome here, the isCommonUser computed is wrong.
Step 2.5 — Stop the dev server
When verification is complete, stop the dev server (Ctrl-C in the terminal where it is running).
- Step 2 completed
Task 3: Commit
Step 3.1 — Stage and review
git status --short
git diff src/layout/index.vue
Expected: only src/layout/index.vue is modified. No stray changes from your edits.
Step 3.2 — Commit
git add src/layout/index.vue
git commit -m "$(cat <<'EOF'
feat(layout): common 角色隐藏侧栏/顶栏/tagsview 并全屏渲染 app-main
根据 useUserStore().roles 是否包含 'common' 隐藏 sidebar、navbar、
tags-view、Settings 浮动按钮,并让 main-container 在该模式下全屏铺满。
仅修改 src/layout/index.vue。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
EOF
)"
Expected: one new commit on top of b193fa1. Working tree should be clean (modulo any pre-existing changes unrelated to this task — those are not part of this plan).
- Step 3 completed
Self-Review Checklist
- Spec coverage:
- Goal (hide chrome + fullscreen app-main for
commonrole) → Task 1 - Trigger (
roles.includes('common')) → Step 1.1 - All four chrome elements gated → Steps 1.2 edits 1, 3, 4, 5
- Fullscreen class binding on
main-container→ Step 1.2 edit 2 - Fullscreen SCSS rule → Step 1.3
- Manual verification scenarios (admin / common / mixed / page interaction) → Tasks 2.2, 2.3, 2.4
- Settings also hidden (confirmed in brainstorming) → Step 1.2 edit 5
- Goal (hide chrome + fullscreen app-main for
- Placeholder scan: No TBD/TODO. Each edit has exact code. Manual verification steps have concrete URLs and accounts to use (caller supplies).
- Type consistency: All references use
isCommonUser. No alternate naming introduced.useUserStorematches existing imports elsewhere (@/store/modules/user). - Commit hygiene: One focused commit. Message starts with
feat(layout):. Co-authored-by line present.