add toolbar and statusbar

This commit is contained in:
Sylvain Schneider
2026-05-11 23:51:24 +02:00
parent e9e334cdcb
commit d4248775b9
4 changed files with 252 additions and 4 deletions

View File

@@ -1,17 +1,42 @@
<script setup lang="ts">
import AppMenubar from './components/AppMenubar.vue'
import AppToolbar from './components/AppToolbar.vue'
import AppStatusbar from './components/AppStatusbar.vue'
import RequirementsView from './views/RequirementsView.vue'
</script>
<template>
<div id="app">
<AppMenubar />
<AppToolbar />
<main class="app-main">
<RequirementsView />
</main>
<AppStatusbar />
</div>
</template>
<style>
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#app {
min-height: 100vh;
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.app-main {
flex: 1;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,85 @@
<script setup lang="ts">
import { computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useRequirementsStore } from '../stores/requirements'
const requirementsStore = useRequirementsStore()
const { requirements, selectedRequirement, stats } = storeToRefs(requirementsStore)
const statusMessage = computed(() => {
if (!selectedRequirement.value) {
return 'No requirement selected'
}
return `${selectedRequirement.value.reference} - ${selectedRequirement.value.title}`
})
const detailsMessage = computed(() => {
return `Total: ${stats.value.total} | Approved: ${stats.value.approvedCount} | Blocked: ${stats.value.blockedCount}`
})
</script>
<template>
<footer class="app-statusbar">
<div class="status-section">
<i :class="`pi ${selectedRequirement ? 'pi-check-circle text-success' : 'pi-info-circle text-info'}`" />
<span class="status-text">{{ statusMessage }}</span>
</div>
<div class="status-divider" />
<div class="status-section">
<span class="status-details">{{ detailsMessage }}</span>
</div>
</footer>
</template>
<style scoped>
.app-statusbar {
display: flex;
align-items: center;
height: 2rem;
padding: 0 1rem;
background: rgba(255, 255, 255, 0.95);
border-top: 1px solid rgba(96, 117, 156, 0.16);
font-size: 0.8rem;
color: #6c7b97;
gap: 1rem;
backdrop-filter: blur(12px);
}
.status-section {
display: flex;
align-items: center;
gap: 0.5rem;
overflow: hidden;
text-overflow: ellipsis;
}
.status-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status-details {
white-space: nowrap;
}
.status-divider {
width: 1px;
height: 1rem;
background: rgba(96, 117, 156, 0.14);
}
:deep(.pi) {
font-size: 0.9rem;
}
:deep(.pi.text-success) {
color: #22c55e;
}
:deep(.pi.text-info) {
color: #3b82f6;
}
</style>

View File

@@ -0,0 +1,136 @@
<script setup lang="ts">
import { ref } from 'vue'
import Toolbar from 'primevue/toolbar'
import Button from 'primevue/button'
import Divider from 'primevue/divider'
const emit = defineEmits<{
new: []
open: []
save: []
undo: []
redo: []
}>()
const handleNew = () => emit('new')
const handleOpen = () => emit('open')
const handleSave = () => emit('save')
const handleUndo = () => emit('undo')
const handleRedo = () => emit('redo')
</script>
<template>
<Toolbar class="app-toolbar">
<template #start>
<div class="toolbar-section">
<Button
icon="pi pi-file"
rounded
text
severity="secondary"
@click="handleNew"
v-tooltip="'New'"
/>
<Button
icon="pi pi-folder-open"
rounded
text
severity="secondary"
@click="handleOpen"
v-tooltip="'Open'"
/>
<Button
icon="pi pi-save"
rounded
text
severity="secondary"
@click="handleSave"
v-tooltip="'Save'"
/>
<Divider layout="vertical" />
<Button
icon="pi pi-undo"
rounded
text
severity="secondary"
@click="handleUndo"
v-tooltip="'Undo'"
/>
<Button
icon="pi pi-redo"
rounded
text
severity="secondary"
@click="handleRedo"
v-tooltip="'Redo'"
/>
</div>
</template>
<template #end>
<div class="toolbar-section">
<Button
icon="pi pi-bell"
rounded
text
severity="secondary"
@click="() => console.log('Notifications')"
v-tooltip="'Notifications'"
/>
<Button
icon="pi pi-user"
rounded
text
severity="secondary"
@click="() => console.log('Profile')"
v-tooltip="'Profile'"
/>
</div>
</template>
</Toolbar>
</template>
<style scoped>
.app-toolbar {
border-bottom: 1px solid rgba(96, 117, 156, 0.16);
background: rgba(255, 255, 255, 0.95);
padding: 0.5rem 1rem;
backdrop-filter: blur(12px);
z-index: 999;
}
:deep(.p-toolbar) {
background: transparent;
border: none;
padding: 0;
gap: 0;
}
:deep(.p-toolbar-group-start),
:deep(.p-toolbar-group-end) {
gap: 0;
}
.toolbar-section {
display: flex;
align-items: center;
gap: 0.25rem;
}
:deep(.p-button.p-button-rounded) {
width: 2.5rem;
height: 2.5rem;
}
:deep(.p-divider-vertical) {
height: 1.5rem;
margin: 0 0.5rem;
background: rgba(96, 117, 156, 0.14);
}
:deep(.p-tooltip) {
font-size: 0.75rem;
}
</style>

View File

@@ -88,6 +88,7 @@ const treeData = computed(() => buildTreeData())
<style scoped>
.requirements-view {
padding: 2rem;
min-height: 100%;
background:
radial-gradient(circle at top left, rgba(78, 107, 255, 0.18), transparent 34%),
radial-gradient(circle at top right, rgba(21, 184, 164, 0.14), transparent 28%),
@@ -165,3 +166,4 @@ const treeData = computed(() => buildTreeData())
}
}
</style>