This commit is contained in:
vadim committed 2026-10-05 10:52:49 +03:00
1 parent b80e88b121
commit 51debefee5
13 files changed
+111 -42

No files matched your search

+1 -1
View File
@@ -53,7 +53,7 @@ onMounted(async () => {
<template>
<component :is="layout">
<router-view v-slot="{ Component, route }">
<div :key="route.name">
<div :key="route.name" class="h-100">
<component :is="Component" />
</div>
</router-view>
+6 -7
View File
@@ -160,7 +160,7 @@ function onEnter(e: KeyboardEvent) {
/>
</div>
<div class="chat__bubble">
<v-sheet class="chat__bubble px-4 py-2">
<div v-if="item.showHeader && !item.own" class="font-weight-medium text-body-small text-primary">
{{ authorName(item.comment) }}
</div>
@@ -171,13 +171,13 @@ function onEnter(e: KeyboardEvent) {
<div class="chat__meta text-medium-emphasis">
<span v-if="item.comment.editedAt && !item.comment.deletedAt">edited · </span>{{ item.time }}
</div>
</div>
</v-sheet>
</div>
</template>
</div>
<v-fade-transition>
<v-btn v-if="!atBottom" class="chat__jump" icon size="small" elevation="2" @click="scrollToBottom('smooth')">
<v-btn v-if="!atBottom" density="compact" class="chat__jump" icon @click="scrollToBottom('smooth')">
<v-badge :model-value="unread > 0" :content="unread" color="primary" floating>
<v-icon icon="mdi-chevron-down" />
</v-badge>
@@ -220,7 +220,8 @@ function onEnter(e: KeyboardEvent) {
.chat {
display: flex;
flex-direction: column;
height: min(30vh, 560px);
height: 100%;
min-height: 20rem;
&__viewport {
position: relative;
@@ -271,12 +272,10 @@ function onEnter(e: KeyboardEvent) {
&__bubble {
max-width: min(75%, 640px);
min-width: 0;
padding: 6px 10px;
border-radius: 14px;
background: rgba(var(--v-theme-on-surface), 0.06);
.chat__row--own & {
background: rgba(var(--v-theme-primary), 0.14);
background: rgba(var(--v-theme-primary), 0.35);
}
}
+10 -2
View File
@@ -46,10 +46,18 @@ const open = () => {
<v-btn density="compact" size="small" :icon="icon" @click="open" />
<div @click="open" class="font-weight-bold text-capitalize text-title-medium cursor-pointer">{{ title }}</div>
</div>
<div v-if="isOpen" class="ml-6 mt-2">
<div v-if="isOpen" class="panel__body ml-6 mt-2">
<slot />
</div>
</div>
</template>
<style scoped lang="scss"></style>
<style scoped lang="scss">
// Lets the body fill the panel when the panel itself is stretched by its parent
.panel__body {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
</style>
+5 -4
View File
@@ -33,7 +33,7 @@ const cancel = () => {
<v-hover #default="{ isHovering, props }">
<v-sheet
v-bind="props"
:class="isHovering ? 'px-4' : 'px-0'"
:class="isHovering ? 'px-0' : 'px-0'"
class="py-1 cursor-pointer content-sheet"
@click="startEdit"
>
@@ -59,9 +59,10 @@ const cancel = () => {
overflow-wrap: anywhere;
}
.content-sheet:hover {
background-color: rgba(var(--v-theme-on-surface), 0.06);
}
//.content-sheet:hover {
//background-color: rgba(var(--v-theme-on-surface), 0.06);
//}
.v-sheet {
transition: padding 0.2s ease-in-out;
}
-1
View File
@@ -49,7 +49,6 @@ const cancel = () => {
<v-date-input
input-format="dd-mm-yyyy"
autofocus
class="mb-1"
hide-details
prepend-icon=""
v-model="draft"
+49 -16
View File
@@ -31,9 +31,7 @@ const { ckey } = defineProps<Props>()
const createdAtFormatted = computed(() => {
if (!issue.value?.createdAt) return ''
return new Intl.DateTimeFormat('ru-RU', { dateStyle: 'medium', timeStyle: 'short' }).format(
new Date(issue.value.createdAt),
)
return new Date(issue.value.createdAt).toLocaleString('ru-RU')
})
async function fetch() {
@@ -101,7 +99,8 @@ defineExpose({
</script>
<template>
<div v-if="issue" class="d-flex flex-column ga-4 pa-4">
<div v-if="issue" class="pa-4 details">
<div class="d-flex flex-column ga-4">
<div>{{ ckey }}</div>
<issue-title :text="issue.title" @changed="onTitleChanged" />
@@ -128,18 +127,17 @@ defineExpose({
<expansion-panel title="Details">
<issue-content :text="issue.content" @changed="onContentChanged" />
</expansion-panel>
</div>
<div class="d-flex flex-column">
<expansion-panel title="Activity" class="activity">
<v-sheet class="activity__sheet">
<v-btn-toggle class="align-self-start" border divided v-model="activity" mandatory="force" density="compact">
<v-btn rounded="0" prepend-icon="mdi-chat" value="comment">Comments</v-btn>
<v-btn rounded="0" prepend-icon="mdi-history" value="history">History</v-btn>
</v-btn-toggle>
<expansion-panel title="Activity">
<v-sheet>
<v-tabs v-model="activity" density="compact">
<v-tab prepend-icon="mdi-star" value="comment">Comments</v-tab>
<v-tab prepend-icon="mdi-star" value="history">History</v-tab>
</v-tabs>
<v-divider />
<v-tabs-window v-model="activity">
<v-tabs-window-item value="comment">
<v-tabs-window v-model="activity" class="activity__window">
<v-tabs-window-item value="comment" class="h-100">
<comments-list :issue-id="issue.id" />
</v-tabs-window-item>
<v-tabs-window-item value="history">
@@ -149,14 +147,49 @@ defineExpose({
</v-sheet>
</expansion-panel>
</div>
</div>
</template>
<style scoped lang="scss">
.details {
flex: 1;
min-height: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.details > * {
min-height: 0;
overflow-y: auto;
}
.activity {
flex: 1;
min-height: 0;
&__sheet {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
&__window {
flex: 1;
min-height: 0;
:deep(.v-window__container) {
height: 100%;
}
}
}
.u-grid {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
column-gap: 1rem;
row-gap: 0.75rem;
row-gap: 1.5rem;
}
</style>
+4 -4
View File
@@ -33,7 +33,7 @@ const cancel = () => {
<v-hover #default="{ isHovering, props }">
<v-sheet
v-bind="props"
:class="isHovering ? 'px-3' : 'px-0'"
:class="isHovering ? 'px-0' : 'px-0'"
class="py-1 cursor-pointer title-sheet"
@click="startEdit"
>
@@ -56,9 +56,9 @@ const cancel = () => {
</template>
<style scoped lang="scss">
.title-sheet:hover {
background-color: rgba(var(--v-theme-on-surface), 0.06);
}
//.title-sheet:hover {
// background-color: rgba(var(--v-theme-on-surface), 0.06);
//}
.v-sheet {
transition: padding 0.2s ease-in-out;
+20 -2
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import { authClient } from '@/lib/auth-client.ts'
import { computed, ref } from 'vue'
import ProjectMenu from '@/components/ProjectMenu.vue'
@@ -9,6 +9,7 @@ import { useThemeMode } from '@/composables/useThemeMode.ts'
import { THEME_ICONS } from '@/lib/theme.ts'
const router = useRouter()
const route = useRoute()
const session = authClient.useSession()
const { mode: themeMode, cycleThemeMode } = useThemeMode()
@@ -59,6 +60,10 @@ async function goToSignOut() {
const goToSettings = () => {
router.push({ name: 'settings' })
}
const fluid = computed(() => {
return route.meta.fluid !== undefined ? !!route.meta.fluid : true
})
</script>
<template>
@@ -141,12 +146,14 @@ const goToSettings = () => {
</div>
</v-app-bar>
<v-main>
<v-container :fluid="false">
<v-container :fluid="fluid" class="layout-container">
<div class="nav-row d-flex align-center ga-2 mb-2">
<back-button />
<app-breadcrumbs />
</div>
<div class="layout-content">
<slot></slot>
</div>
</v-container>
</v-main>
</v-layout>
@@ -156,4 +163,15 @@ const goToSettings = () => {
.nav-row:empty {
display: none;
}
.layout-container {
height: calc(100dvh - var(--v-layout-top) - var(--v-layout-bottom));
display: flex;
flex-direction: column;
}
.layout-content {
flex: 1;
min-height: 0;
}
</style>
+3
View File
@@ -75,6 +75,9 @@ const vuetify = createVuetify({
density: 'compact',
hideDetails: true,
},
VCard: {
elevation: 0,
},
},
})
+2 -1
View File
@@ -16,6 +16,7 @@ declare module 'vue-router' {
breadcrumb?: string | ((route: RouteLocationNormalizedLoaded) => string)
/** Named route the back button should navigate to, when deep-linking means history may be empty. */
backTo?: string
fluid?: boolean
}
}
@@ -25,7 +26,7 @@ const router = createRouter({
{
path: '/',
component: HomeView,
meta: { layout: 'Default' },
meta: { layout: 'Default', fluid: false },
},
{
name: 'sign-in',
+1
View File
@@ -20,6 +20,7 @@ export const issuesRoutes: RouteRecordRaw = {
meta: {
breadcrumb: (route) => route.params.ckey as string,
backTo: 'issues',
fluid: false,
},
},
],
+1 -1
View File
@@ -24,7 +24,7 @@ watchEffect(async () => fetch())
</script>
<template>
<v-sheet border>
<v-sheet border class="h-100 d-flex flex-column">
<issue-details :ckey="ckey" />
</v-sheet>
</template>
+9 -3
View File
@@ -183,7 +183,7 @@ async function onDeleteBatch() {
</script>
<template>
<div class="d-flex flex-column ga-2">
<div class="d-flex flex-column ga-2 h-100">
<div class="u-grid ga-1">
<div class="u-height">
<issue-filter
@@ -274,7 +274,7 @@ async function onDeleteBatch() {
</div>
</div>
<v-sheet border v-if="selected.length" class="overflow-y-auto">
<v-sheet border v-if="selected.length" class="d-flex flex-column">
<div class="d-flex align-center ga-2 px-4 py-2">
<div>Work item</div>
<v-spacer />
@@ -297,9 +297,15 @@ async function onDeleteBatch() {
.u-grid {
display: grid;
grid-template-columns: v-bind(gridTemplate);
flex: 1;
min-height: 0;
}
.u-grid > * {
min-height: 0;
}
.u-height {
height: calc(100vh - 10rem);
overflow-y: auto;
}
</style>