Skip to content

Commit 3ea5945

Browse files
authored
Merge pull request #21 from smartlabsAT/release/v0.2.6
Release v0.2.6
2 parents 89a7ecc + 519312d commit 3ea5945

10 files changed

Lines changed: 221 additions & 54 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ claude.md
77
/.idea/
88
/.claude/
99
.DS_Store
10-
**/.DS_Store
10+
**/.DS_Store
11+
/release/
12+
*.tar.gz

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@ All notable changes to the Super Layout Table Extension will be documented in th
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.6] - 2025-08-21
9+
10+
### Added
11+
- Smart hover preview for images that follows mouse position (Issue #6)
12+
- Column alignment support for ColorCell component
13+
- Proper aspect ratio preservation for all images
14+
15+
### Changed
16+
- Image display now uses `object-fit: contain` to show complete images without cropping
17+
- File browser thumbnails increased from 60px to 140px for better visibility
18+
- Hover preview dynamically positions to avoid screen edges
19+
20+
### Fixed
21+
- Images being cropped in table cells and file browser (Issue #6)
22+
- Column alignment not working for image and color cells
23+
- Cursor showing as `not-allowed` when hovering over cells in non-edit mode
24+
- Navigation to detail page blocked by incorrect cursor styles
25+
826
## [0.2.5] - 2025-08-21
927

1028
### Fixed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ A powerful and feature-rich table layout extension for Directus 11+ that enhance
1010

1111
## Version
1212

13-
v0.2.3 - Stable release
13+
v0.2.6 - Stable release
1414

1515
## 🌟 Top Features
1616

@@ -29,8 +29,8 @@ Powerful search functionality across all table fields, including nested relation
2929
### 👁️ View & Edit Mode
3030
Switch seamlessly between read-only view mode and interactive edit mode. Control when and how users can modify data.
3131

32-
### 🖼️ Advanced Image Selector
33-
Built-in file browser with image preview for selecting and managing media files directly from table cells.
32+
### 🖼️ Advanced Image Display & Selection
33+
Smart image handling with hover preview, proper aspect ratios, and built-in file browser for selecting media files directly from table cells.
3434

3535
### 🔄 Deep Duplication
3636
Duplicate items with all their relationships and translations. Perfect for creating variations of complex data structures.
@@ -130,9 +130,9 @@ Edit data directly in the table without opening a separate form:
130130
- Text fields: Simple input or WYSIWYG editor
131131
- Boolean: Checkbox toggle
132132
- Select: Dropdown menu
133-
- Date/Time: Full date picker with calendar (✨ NEW in v0.2.3)
134-
- Color: Color picker
135-
- Image/File: Advanced file browser with preview
133+
- Date/Time: Full date picker with calendar
134+
- Color: Color picker with alignment support
135+
- Image/File: Enhanced file browser with larger previews (✨ IMPROVED in v0.2.6)
136136
3. **Unified Header Actions** (✨ NEW in v0.2.3):
137137
- Save/Cancel buttons now in popover header for all field types
138138
- Consistent UI across all editors

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default [
1717
{
1818
ignores: [
1919
'dist/**',
20+
'release/**',
2021
'node_modules/**',
2122
'playwright-tools/**',
2223
'*.config.js',

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "directus-extension-super-table",
3-
"version": "0.2.5",
3+
"version": "0.2.6",
44
"type": "module",
55
"directus:extension": {
66
"type": "layout",

src/components/CellRenderers/ColorCell.vue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!-- ./extensions/layouts/super-layout-table/components/CellRenderers/ColorCell.vue -->
22
<template>
3-
<div class="color-cell">
3+
<div class="color-cell" :class="`align-${alignment || 'left'}`">
44
<div
55
v-if="colorValue"
66
class="color-display"
@@ -33,6 +33,7 @@ const props = defineProps<{
3333
item?: any;
3434
field?: string;
3535
editMode?: boolean;
36+
alignment?: 'left' | 'center' | 'right';
3637
}>();
3738
3839
const { useNotificationsStore } = useStores();
@@ -96,6 +97,20 @@ async function copyToClipboard() {
9697
display: flex;
9798
align-items: center;
9899
min-height: 32px;
100+
width: 100%;
101+
}
102+
103+
/* Alignment variations */
104+
.color-cell.align-left {
105+
justify-content: flex-start;
106+
}
107+
108+
.color-cell.align-center {
109+
justify-content: center;
110+
}
111+
112+
.color-cell.align-right {
113+
justify-content: flex-end;
99114
}
100115
101116
.color-display {

src/components/CellRenderers/ImageCell.vue

Lines changed: 129 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
11
<!-- ./extensions/layouts/super-layout-table/components/CellRenderers/ImageCell.vue -->
22
<template>
3-
<div class="image-cell">
4-
<div v-if="imageSrc" class="image-wrapper">
3+
<div class="image-cell" :class="`align-${alignment || 'center'}`">
4+
<div
5+
v-if="imageSrc"
6+
class="image-wrapper"
7+
@mouseenter="handleMouseEnter"
8+
@mouseleave="showPreview = false"
9+
>
510
<img :src="imageSrc" :alt="alt || 'Preview'" class="preview-image" @error="onImageError" />
611
</div>
712
<span v-else class="image-empty">—</span>
13+
14+
<!-- Hover preview außerhalb des Wrappers mit v-show -->
15+
<Teleport to="body" v-if="imageSrc">
16+
<div
17+
v-show="showPreview"
18+
class="image-hover-preview"
19+
:style="previewStyle"
20+
@mouseenter="showPreview = true"
21+
@mouseleave="showPreview = false"
22+
>
23+
<img :src="imageSrc" :alt="alt || 'Preview'" />
24+
</div>
25+
</Teleport>
826
</div>
927
</template>
1028

@@ -21,9 +39,13 @@ const props = defineProps<{
2139
value?: string | ImageValue | null;
2240
item?: any;
2341
field?: string;
42+
alignment?: 'left' | 'center' | 'right';
2443
}>();
2544
2645
const imageError = ref(false);
46+
const showPreview = ref(false);
47+
const mouseX = ref(0);
48+
const mouseY = ref(0);
2749
2850
const imageSrc = computed(() => {
2951
if (!props.value || imageError.value) return null;
@@ -48,6 +70,42 @@ const alt = computed(() => {
4870
return props.field || 'Image';
4971
});
5072
73+
// Dynamische Position basierend auf Mausposition mit Offset
74+
const previewStyle = computed(() => {
75+
const offset = 20; // Offset von der Maus
76+
const previewWidth = 400;
77+
const previewHeight = 400;
78+
const windowWidth = window.innerWidth;
79+
const windowHeight = window.innerHeight;
80+
81+
let left = mouseX.value + offset;
82+
let top = mouseY.value - previewHeight / 2; // Vertikal zentriert zur Maus
83+
84+
// Wenn Preview rechts aus dem Fenster ragt, links von der Maus anzeigen
85+
if (left + previewWidth > windowWidth - 20) {
86+
left = mouseX.value - previewWidth - offset;
87+
}
88+
89+
// Sicherstellen dass Preview nicht aus dem Fenster ragt
90+
if (left < 20) left = 20;
91+
if (top < 20) top = 20;
92+
if (top + previewHeight > windowHeight - 20) {
93+
top = windowHeight - previewHeight - 20;
94+
}
95+
96+
return {
97+
left: `${left}px`,
98+
top: `${top}px`,
99+
transform: 'none', // Kein transform mehr nötig
100+
};
101+
});
102+
103+
function handleMouseEnter(event: MouseEvent) {
104+
showPreview.value = true;
105+
mouseX.value = event.clientX;
106+
mouseY.value = event.clientY;
107+
}
108+
51109
function onImageError() {
52110
imageError.value = true;
53111
}
@@ -57,44 +115,95 @@ function onImageError() {
57115
.image-cell {
58116
display: flex;
59117
align-items: center;
60-
justify-content: center;
61118
width: 100%;
62119
padding: 2px;
63-
/* Contained height */
64-
height: fit-content;
120+
height: 100%;
121+
}
122+
123+
/* Alignment variations */
124+
.image-cell.align-left {
125+
justify-content: flex-start;
126+
}
127+
128+
.image-cell.align-center {
129+
justify-content: center;
130+
}
131+
132+
.image-cell.align-right {
133+
justify-content: flex-end;
65134
}
66135
67136
.image-wrapper {
68137
position: relative;
69138
border-radius: 4px;
70-
overflow: hidden;
71139
background: var(--background-subdued);
72140
border: 1px solid var(--border-color);
73-
/* Start small, grow with column width */
74-
width: min(100%, max(60px, 80%));
75-
/* Maintain aspect ratio */
76-
aspect-ratio: 16/10;
77-
/* Start with reasonable height */
78-
height: auto;
79-
min-height: 32px;
80-
max-height: 150px;
141+
/* Kompakter Thumbnail der in normale Rows passt */
142+
width: 60px;
143+
height: 40px;
144+
display: flex;
145+
align-items: center;
146+
justify-content: center;
147+
overflow: visible; /* Allow hover preview to overflow */
81148
}
82149
83150
.preview-image {
84151
display: block;
85-
width: 100%;
86-
height: 100%;
87-
object-fit: cover;
88-
transition: transform 0.2s ease;
152+
max-width: calc(100% - 4px);
153+
max-height: calc(100% - 4px);
154+
width: auto;
155+
height: auto;
156+
object-fit: contain; /* Zeigt das komplette Bild ohne Abschneiden */
157+
object-position: center;
158+
}
159+
160+
/* Hover preview tooltip - Fixed positioning */
161+
.image-hover-preview {
162+
position: fixed;
163+
width: 400px;
164+
height: 400px;
165+
background: white;
166+
border: 1px solid #e0e0e0;
167+
border-radius: 8px;
168+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
169+
display: flex;
170+
align-items: center;
171+
justify-content: center;
172+
z-index: 9999;
173+
padding: 12px;
174+
pointer-events: auto; /* Wichtig für mouseenter/leave */
175+
transition: opacity 0.2s ease;
176+
}
177+
178+
.image-hover-preview img {
179+
max-width: 100%;
180+
max-height: 100%;
181+
object-fit: contain;
182+
border-radius: 4px;
89183
}
90184
91-
.image-wrapper:hover .preview-image {
185+
.image-wrapper:hover {
186+
cursor: zoom-in;
187+
border-color: var(--primary);
92188
transform: scale(1.05);
93-
cursor: pointer;
189+
transition: all 0.2s ease;
94190
}
95191
96192
.image-empty {
97193
color: var(--foreground-subdued);
98194
font-style: italic;
99195
}
196+
197+
/* Bessere Responsivität für schmale Spalten */
198+
@media (max-width: 768px) {
199+
.image-wrapper {
200+
width: 80px;
201+
height: 60px;
202+
}
203+
204+
.image-hover-preview {
205+
width: 300px;
206+
height: 300px;
207+
}
208+
}
100209
</style>

src/components/EditableCellRelational.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
:item="item"
3737
:field="actualFieldKey"
3838
:edit-mode="props.editMode"
39+
:alignment="props.align"
3940
/>
4041
<!-- Use custom ImageCell for image fields -->
4142
<ImageCell
@@ -51,6 +52,7 @@
5152
:value="value"
5253
:item="item"
5354
:field="actualFieldKey"
55+
:alignment="align"
5456
/>
5557
<!-- Use custom RelationalCell for relational fields -->
5658
<RelationalCell

0 commit comments

Comments
 (0)