Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
71c1bf1
[topbar] align budget icon gray with other section icons
frankrousseau May 8, 2026
c5e2161
[loading] replace spinner with staggered skeleton rows
frankrousseau May 8, 2026
3609169
[profile] redesign 2FA section as stacked method cards
frankrousseau May 10, 2026
edd7629
[widgets] Inset toggle knob inside its track
frankrousseau May 10, 2026
3079905
[profile] Redesign profile page
frankrousseau May 10, 2026
a54b795
[avatar] Crop avatar on the client before upload
frankrousseau May 10, 2026
f94cdff
[plugins] Render plugin icons at the right size in nav
frankrousseau May 10, 2026
7ccf6de
[notifications] Migrate page to Composition API
frankrousseau May 11, 2026
2b47c64
[notifications] Responsive layout and notification card tweaks
frankrousseau May 11, 2026
9e596f2
[notifications] Restructure card into two rows
frankrousseau May 11, 2026
a8b44a3
[avatar] Make the preview circle the centerpiece of the modal
frankrousseau May 11, 2026
eb348b7
[widgets] Extract ImageCropper and reuse it for production picture
frankrousseau May 11, 2026
fecc5e6
[playlists] Redesign the Share playlist modal
frankrousseau May 11, 2026
17fac7a
[avatar] Allow the change-avatar modal to use a rounded shape
frankrousseau May 11, 2026
9e682f2
[settings] Restyle the page in the same shape as Profile
frankrousseau May 11, 2026
fca5f83
[widgets] Add Card widget and disconnect per-section save loading
frankrousseau May 11, 2026
e01e555
[asset-library] Migrate page to Composition API
frankrousseau May 11, 2026
54cc5b6
[asset-library] Make the page responsive
frankrousseau May 11, 2026
9bd2e87
[asset-types] Migrate page and list to Composition API
frankrousseau May 11, 2026
54f6307
[asset-types] Stack rows as cards on mobile
frankrousseau May 11, 2026
4748673
[departments] Migrate page and list to Composition API
frankrousseau May 11, 2026
5ef594f
[departments] Hide the available-items column on mobile
frankrousseau May 11, 2026
01ddc0f
[task-status] Migrate page and list to Composition API
frankrousseau May 11, 2026
84888bc
[task-status] Reorder columns and add hover-fly actions
frankrousseau May 11, 2026
54ef722
[hardware-items] Migrate page and list to Composition API
frankrousseau May 11, 2026
a753c7b
[budget] Migrate SalaryScale to Composition API and add mobile layout
frankrousseau May 12, 2026
f421110
[software-licenses] Migrate page+list and fix mobile card backgrounds
frankrousseau May 12, 2026
ddd771c
[previews] Fix download URL for non-mp4 files in shared playlists
frankrousseau May 12, 2026
0826adf
[task-types] Migrate page and list to Composition API
frankrousseau May 12, 2026
ab8c3ae
[annotations] Keep modifications until save succeeds, retry on error
frankrousseau May 12, 2026
8d1d1d4
[task-status] Disable drag-and-drop on mobile
frankrousseau May 12, 2026
e432bf9
[entity-search] Migrate to Composition API and polish mobile layout
frankrousseau May 12, 2026
c0daf1a
[news] Migrate page, extract NewsRow/NewsSkeleton/NewsFilters, polish…
frankrousseau May 12, 2026
bd7e613
[news] Mobile responsive: slide-in drawer + simplified timeline
frankrousseau May 13, 2026
c2705ba
[preview] Fix image not stretching to fit in fullscreen
frankrousseau May 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,14 @@ th.validation-cell {
height: 43px;
}

// vue-date-picker's default dark border (`#2d2d2d`) is too low-contrast
// against the picker background. Bump it just enough to read as a
// border without dominating, and keep the library defaults for
// everything else (background, hover/focus stay untouched).
.dp__theme_dark {
--dp-border-color: #3a3a3a !important;
}

#app .v3-emoji-picker.v3-color-theme-dark .v3-sticky {
text-transform: uppercase;
font-size: 0.8em;
Expand Down
2 changes: 1 addition & 1 deletion src/components/cells/TaskStatusCell.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<td class="name">
<td>
<div
class="tag"
:class="{ canceled: disable }"
Expand Down
7 changes: 6 additions & 1 deletion src/components/lists/AllTaskList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,12 @@
{{ $t('main.load_more') }}
</button>
</div>
<table-info :is-loading="isLoading" :is-error="isError" />
<table-info
:is-loading="isLoading"
:is-error="isError"
:cells="10"
:with-actions="false"
/>
</div>
<p class="has-text-centered nb-tasks" v-if="!isLoading">
{{ stats.total }}
Expand Down
2 changes: 1 addition & 1 deletion src/components/lists/AssetList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@
<p class="info">{{ $t('assets.empty_list_client') }}</p>
</div>

<table-info :is-loading="isLoading" :is-error="isError" />
<table-info :is-loading="isLoading" :is-error="isError" big-cells />
</div>

<asset-list-numbers
Expand Down
168 changes: 122 additions & 46 deletions src/components/lists/AssetTypeList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,38 @@
</thead>
<tbody class="datatable-body" v-if="entries.length">
<tr class="datatable-row" v-for="entry in entries" :key="entry.id">
<td class="name">
<td class="name" :data-label="$t('asset_types.fields.name')">
{{ entry.name }}
<span :title="entry.description" v-if="entry.description">
<help-circle-icon class="icon is-small" />
</span>
</td>
<td class="short-name">
<td
class="short-name"
:data-label="$t('asset_types.fields.short_name')"
v-if="entry.short_name"
>
{{ entry.short_name }}
</td>
<td class="task-types" v-if="entry.task_types?.length">
<td class="short-name" v-else></td>
<td
class="task-types"
:data-label="$t('asset_types.fields.task_types')"
v-if="entry.task_types?.length"
>
<span
:key="taskType.id"
class="task-type-name flexrow-item"
v-for="taskType in sortTaskTypes(entry.task_types)"
v-for="taskType in sortedTaskTypes(entry.task_types)"
>
<task-type-name :task-type="taskType" v-if="taskType.id" />
</span>
</td>
<td class="task-types" v-else>
<td
class="task-types"
:data-label="$t('asset_types.fields.task_types')"
v-else
>
{{ $t('asset_types.include_all') }}
</td>
<row-actions-cell
Expand All @@ -48,64 +61,52 @@
</table>
</div>

<table-info :is-loading="isLoading" :is-error="isError"> </table-info>
<table-info
:is-loading="isLoading"
:is-error="isError"
:cells="2"
:with-thumbnail="false"
/>

<p class="has-text-centered nb-asset-types">
{{ entries.length }} {{ $tc('asset_types.number', entries.length) }}
{{ entries.length }} {{ $t('asset_types.number', entries.length) }}
</p>
</div>
</template>

<script>
<script setup>
import { HelpCircleIcon } from 'lucide-vue-next'
import { mapGetters } from 'vuex'
import { computed } from 'vue'
import { useStore } from 'vuex'

import { sortTaskTypes } from '@/lib/sorting'

import RowActionsCell from '@/components/cells/RowActionsCell.vue'
import TableInfo from '@/components/widgets/TableInfo.vue'
import TaskTypeName from '@/components/widgets/TaskTypeName.vue'

export default {
name: 'asset-type-list',

components: {
HelpCircleIcon,
RowActionsCell,
TableInfo,
TaskTypeName
},

props: {
entries: {
type: Array,
default: () => []
},
isError: {
type: Boolean,
default: false
},
isLoading: {
type: Boolean,
default: false
}
},
const store = useStore()

emits: ['delete-clicked', 'edit-clicked'],
defineProps({
entries: { type: Array, default: () => [] },
isError: { type: Boolean, default: false },
isLoading: { type: Boolean, default: false }
})

computed: {
...mapGetters(['taskTypeMap'])
},
defineEmits(['delete-clicked', 'edit-clicked'])

methods: {
sortTaskTypes(taskTypeIds) {
const taskTypes =
taskTypeIds
?.map(taskTypeId => this.taskTypeMap.get(taskTypeId))
.filter(Boolean) ?? []
return sortTaskTypes(taskTypes)
}
}
// Computed

const taskTypeMap = computed(() => store.getters.taskTypeMap)

// Functions

const sortedTaskTypes = taskTypeIds => {
const taskTypes =
taskTypeIds
?.map(taskTypeId => taskTypeMap.value.get(taskTypeId))
.filter(Boolean) ?? []
return sortTaskTypes(taskTypes)
}
</script>

Expand All @@ -119,4 +120,79 @@ export default {
width: 300px;
padding: 1em;
}

@media screen and (max-width: 768px) {
// Turn each row into a card: the table head disappears, every cell is
// labelled via its data-label attribute, and the actions cell collapses
// to a footer row. Keep the wrapper's overflow-y: auto from the global
// .datatable-wrapper rule so the list still scrolls inside .fixed-page.
:deep(.datatable-wrapper) {
background: transparent;
border: 0;
overflow-x: visible;
}

.datatable,
.datatable-body {
display: block;
width: 100%;
}

.datatable-head {
display: none;
}

.datatable-row {
background: var(--background);
border: 1px solid var(--border);
border-radius: 12px;
display: block;
margin-bottom: 0.75em;
padding: 0.85em 1em;
}

.dark .datatable-row {
background: var(--background-alt);
}

.datatable-row td {
border: 0;
display: block;
padding: 0.4em 0;
width: auto;
}

// Cells without a data-label are placeholders to keep the desktop
// table columns aligned — collapse them on mobile so empty fields
// don't leave gaps.
.datatable-row td:not([data-label]):not(.actions):not(.name) {
display: none;
}

.datatable-row td[data-label]::before {
color: var(--text-alt);
content: attr(data-label);
display: block;
font-size: 0.75em;
letter-spacing: 0.06em;
margin-bottom: 0.2em;
text-transform: uppercase;
}

// The name doubles as the card title — drop its label and bump the
// font weight.
.datatable-row .name {
font-size: 1.05em;
font-weight: 600;
padding-top: 0;

&::before {
display: none;
}
}

.datatable-row .actions {
display: none;
}
}
</style>
2 changes: 1 addition & 1 deletion src/components/lists/BackgroundList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
</table>
</div>

<table-info :is-loading="isLoading" :is-error="isError" />
<table-info :is-loading="isLoading" :is-error="isError" :cells="1" />

<p class="has-text-centered">
{{ entries.length }}
Expand Down
7 changes: 6 additions & 1 deletion src/components/lists/CustomActionList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@
</table>
</div>

<table-info :is-loading="isLoading" :is-error="isError" />
<table-info
:is-loading="isLoading"
:is-error="isError"
:cells="3"
:with-thumbnail="false"
/>

<p class="has-text-centered nb-custom-actions">
{{ entries.length }} {{ $t('custom_actions.number', entries.length) }}
Expand Down
7 changes: 6 additions & 1 deletion src/components/lists/DayOffList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@
<p>{{ $t('days_off.no_days_off') }}</p>
</div>

<table-info :is-loading="isLoading" :is-error="isError" />
<table-info
:is-loading="isLoading"
:is-error="isError"
:cells="1"
:with-thumbnail="false"
/>

<p class="has-text-centered footer-info" v-if="!isLoading">
{{ sortedDaysOff.length }}
Expand Down
Loading