@stellartech/image-style-widget-directus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,258 @@
1
+ <template>
2
+ <div
3
+ class="style-card"
4
+ :class="{ 'style-card--selected': isSelected }"
5
+ >
6
+ <!-- Images Section -->
7
+ <div class="style-card__images">
8
+ <div class="style-card__image">
9
+ <img
10
+ v-if="style.example_1"
11
+ :src="getFileUrl(style.example_1)"
12
+ :alt="`${style.name} example 1`"
13
+ />
14
+ <div v-else class="style-card__placeholder">
15
+ <v-icon name="image" />
16
+ </div>
17
+ </div>
18
+ <div class="style-card__image">
19
+ <img
20
+ v-if="style.example_2"
21
+ :src="getFileUrl(style.example_2)"
22
+ :alt="`${style.name} example 2`"
23
+ />
24
+ <div v-else class="style-card__placeholder">
25
+ <v-icon name="image" />
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <!-- Content Section -->
31
+ <div class="style-card__content">
32
+ <!-- Header: Radio + Name -->
33
+ <div class="style-card__header">
34
+ <label class="style-card__radio">
35
+ <input
36
+ type="radio"
37
+ :checked="isSelected"
38
+ :name="radioGroupName"
39
+ @change="$emit('select', style.id)"
40
+ />
41
+ <span class="style-card__radio-custom"></span>
42
+ </label>
43
+ <h3 class="style-card__name">{{ style.name }}</h3>
44
+ </div>
45
+
46
+ <!-- Prompt Preview -->
47
+ <p class="style-card__prompt">{{ truncatedPrompt }}</p>
48
+
49
+ <!-- Actions -->
50
+ <div class="style-card__actions">
51
+ <!-- Hidden for now - set v-if="true" to restore -->
52
+ <button
53
+ v-if="false"
54
+ class="style-card__btn style-card__btn--secondary"
55
+ :disabled="loading"
56
+ @click="$emit('edit', style)"
57
+ >
58
+ <v-icon name="edit" small />
59
+ <span>Edit Prompt</span>
60
+ </button>
61
+ <button
62
+ class="style-card__btn style-card__btn--secondary"
63
+ :disabled="loading"
64
+ @click="$emit('regenerate', style)"
65
+ >
66
+ <v-icon name="refresh" small />
67
+ <span>{{ loading ? 'Generating...' : 'Generate an example' }}</span>
68
+ </button>
69
+ <button
70
+ class="style-card__btn"
71
+ :class="{ 'style-card__btn--primary': isSelected }"
72
+ @click="$emit('select', style.id)"
73
+ >
74
+ <v-icon :name="isSelected ? 'radio_button_checked' : 'radio_button_unchecked'" small />
75
+ <span>Select</span>
76
+ </button>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ import { computed } from 'vue';
84
+ import type { Style } from '../composables/useDirectusApi';
85
+
86
+ const props = defineProps<{
87
+ style: Style;
88
+ isSelected: boolean;
89
+ radioGroupName: string;
90
+ loading?: boolean;
91
+ getFileUrl: (fileId: string | null) => string;
92
+ }>();
93
+
94
+ defineEmits<{
95
+ (e: 'select', styleId: string): void;
96
+ (e: 'edit', style: Style): void;
97
+ (e: 'regenerate', style: Style): void;
98
+ }>();
99
+
100
+ const truncatedPrompt = computed(() => {
101
+ const maxLength = 100;
102
+ if (props.style.prompt.length <= maxLength) return props.style.prompt;
103
+ return props.style.prompt.substring(0, maxLength) + '...';
104
+ });
105
+ </script>
106
+
107
+ <style scoped>
108
+ .style-card {
109
+ display: flex;
110
+ gap: 20px;
111
+ padding: 16px;
112
+ border: 2px solid var(--theme--border-color-subdued, #e0e0e0);
113
+ border-radius: 8px;
114
+ background: var(--theme--background, #fff);
115
+ transition: all 0.2s ease;
116
+ }
117
+
118
+ .style-card:hover {
119
+ border-color: var(--theme--border-color, #ccc);
120
+ }
121
+
122
+ .style-card--selected {
123
+ border-color: var(--theme--primary, #6644ff);
124
+ background: var(--theme--primary-background, #f5f3ff);
125
+ }
126
+
127
+ .style-card__images {
128
+ display: flex;
129
+ gap: 8px;
130
+ flex-shrink: 0;
131
+ }
132
+
133
+ .style-card__image {
134
+ width: 80px;
135
+ height: 80px;
136
+ border-radius: 6px;
137
+ overflow: hidden;
138
+ background: var(--theme--background-subdued, #f5f5f5);
139
+ }
140
+
141
+ .style-card__image img {
142
+ width: 100%;
143
+ height: 100%;
144
+ object-fit: cover;
145
+ }
146
+
147
+ .style-card__placeholder {
148
+ width: 100%;
149
+ height: 100%;
150
+ display: flex;
151
+ align-items: center;
152
+ justify-content: center;
153
+ color: var(--theme--foreground-subdued, #999);
154
+ }
155
+
156
+ .style-card__content {
157
+ flex: 1;
158
+ display: flex;
159
+ flex-direction: column;
160
+ gap: 8px;
161
+ min-width: 0;
162
+ }
163
+
164
+ .style-card__header {
165
+ display: flex;
166
+ align-items: center;
167
+ gap: 10px;
168
+ }
169
+
170
+ .style-card__radio {
171
+ position: relative;
172
+ display: flex;
173
+ align-items: center;
174
+ cursor: pointer;
175
+ }
176
+
177
+ .style-card__radio input {
178
+ position: absolute;
179
+ opacity: 0;
180
+ width: 0;
181
+ height: 0;
182
+ }
183
+
184
+ .style-card__radio-custom {
185
+ width: 18px;
186
+ height: 18px;
187
+ border: 2px solid var(--theme--border-color, #ccc);
188
+ border-radius: 50%;
189
+ transition: all 0.2s ease;
190
+ }
191
+
192
+ .style-card__radio input:checked + .style-card__radio-custom {
193
+ border-color: var(--theme--primary, #6644ff);
194
+ background: var(--theme--primary, #6644ff);
195
+ box-shadow: inset 0 0 0 3px var(--theme--background, #fff);
196
+ }
197
+
198
+ .style-card__name {
199
+ margin: 0;
200
+ font-size: 16px;
201
+ font-weight: 600;
202
+ color: var(--theme--foreground, #333);
203
+ }
204
+
205
+ .style-card__prompt {
206
+ margin: 0;
207
+ font-size: 13px;
208
+ color: var(--theme--foreground-subdued, #666);
209
+ line-height: 1.4;
210
+ flex: 1;
211
+ }
212
+
213
+ .style-card__actions {
214
+ display: flex;
215
+ gap: 8px;
216
+ margin-top: auto;
217
+ }
218
+
219
+ .style-card__btn {
220
+ display: inline-flex;
221
+ align-items: center;
222
+ gap: 4px;
223
+ padding: 6px 12px;
224
+ border: 1px solid var(--theme--border-color, #ccc);
225
+ border-radius: 4px;
226
+ background: var(--theme--background, #fff);
227
+ color: var(--theme--foreground-subdued, #666);
228
+ font-size: 12px;
229
+ cursor: pointer;
230
+ transition: all 0.2s ease;
231
+ }
232
+
233
+ .style-card__btn:hover:not(:disabled) {
234
+ border-color: var(--theme--primary, #6644ff);
235
+ color: var(--theme--primary, #6644ff);
236
+ }
237
+
238
+ .style-card__btn:disabled {
239
+ opacity: 0.5;
240
+ cursor: not-allowed;
241
+ }
242
+
243
+ .style-card__btn--primary {
244
+ background: var(--theme--primary, #6644ff);
245
+ border-color: var(--theme--primary, #6644ff);
246
+ color: #fff;
247
+ }
248
+
249
+ .style-card__btn--primary:hover:not(:disabled) {
250
+ background: var(--theme--primary-accent, #5533ee);
251
+ border-color: var(--theme--primary-accent, #5533ee);
252
+ color: #fff;
253
+ }
254
+
255
+ .style-card__btn--secondary {
256
+ background: transparent;
257
+ }
258
+ </style>