1+ <template >
2+ <div
3+ v-if =" visible"
4+ class =" fixed inset-0 bg-gray-900 bg-opacity-75 flex justify-center items-center p-4"
5+ style =" z-index : 9999 ;"
6+ @click.self =" close"
7+ >
8+ <div class =" bg-white dark:bg-gray-800 rounded-lg w-full max-w-xl flex flex-col shadow-2xl" style =" max-height : 60vh ;" >
9+ <div class =" flex justify-between items-center px-6 py-4 border-b border-gray-200 dark:border-gray-700 flex-shrink-0" >
10+ <h3 class =" font-bold text-lg text-gray-900 dark:text-white" >{{ __('Add Preset') }}</h3 >
11+ <button
12+ @click =" close"
13+ class =" text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 text-2xl leading-none bg-transparent border-0 cursor-pointer transition-colors"
14+ >
15+ × ;
16+ </button >
17+ </div >
18+
19+ <div class =" px-6 py-4 overflow-y-auto flex-1 min-h-0" >
20+ <div v-if =" !selectedPreset" class =" preset-selection" >
21+ <p class =" text-gray-600 dark:text-gray-300 mb-4" >{{ __('Choose a preset to add to your schema:') }}</p >
22+
23+ <div class =" grid grid-cols-1 gap-3" >
24+ <div
25+ v-for =" preset in presets"
26+ :key =" preset.name"
27+ @click =" selectPreset(preset)"
28+ class =" border border-gray-200 dark:border-gray-700 rounded-md p-3 cursor-pointer transition-all duration-200 hover:border-blue-500 hover:shadow-sm hover:shadow-blue-500/10 dark:hover:border-blue-400 bg-white dark:bg-gray-800"
29+ >
30+ <div class =" flex justify-between items-start" >
31+ <div class =" flex-1" >
32+ <h4 class =" font-semibold text-gray-900 dark:text-white text-sm" >{{ preset.name }}</h4 >
33+ <p class =" text-xs text-gray-600 dark:text-gray-300 mt-1" >{{ preset.description }}</p >
34+
35+ <div class =" mt-2" >
36+ <div class =" text-xs text-gray-500 dark:text-gray-400 mb-1" >{{ __('Fields:') }}</div >
37+ <div class =" flex flex-wrap gap-1" >
38+ <span
39+ v-for =" field in preset.schema.fields.slice(0, 3)"
40+ :key =" field.key"
41+ class =" bg-blue-50 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 px-1.5 py-0.5 rounded text-[9px] font-medium"
42+ >
43+ {{ field.key }}
44+ </span >
45+ <span
46+ v-if =" preset.schema.fields.length > 3"
47+ class =" bg-gray-100 dark:bg-gray-600 text-gray-600 dark:text-gray-300 px-1.5 py-0.5 rounded text-[9px]"
48+ >
49+ +{{ preset.schema.fields.length - 3 }}
50+ </span >
51+ </div >
52+ </div >
53+ </div >
54+ <div class =" bg-gray-100 dark:bg-gray-600 text-gray-700 dark:text-gray-200 px-2 py-1 rounded text-xs font-medium ml-2" >
55+ {{ preset.schema.specialProps.type }}
56+ </div >
57+ </div >
58+ </div >
59+ </div >
60+ </div >
61+
62+ <div v-else class =" preset-actions" >
63+ <div class =" mb-4 p-3 bg-blue-50 dark:bg-blue-900/20 rounded border border-blue-200 dark:border-blue-800" >
64+ <h4 class =" font-semibold text-blue-800 dark:text-blue-200" >{{ selectedPreset.name }}</h4 >
65+ <p class =" text-sm text-blue-600 dark:text-blue-300" >{{ selectedPreset.description }}</p >
66+ </div >
67+
68+ <div v-if =" hasExistingSchemas" class =" action-selection" >
69+ <p class =" text-gray-700 dark:text-gray-200 mb-4" >{{ __('You have existing schemas. How would you like to add this preset?') }}</p >
70+
71+ <div class =" flex flex-col gap-3" >
72+ <button
73+ @click =" handleAction('merge')"
74+ class =" border border-gray-200 dark:border-gray-700 rounded-md p-4 text-left cursor-pointer transition-all duration-200 bg-white dark:bg-gray-800 w-full hover:border-green-500 hover:shadow-md hover:shadow-green-500/10 dark:hover:border-green-400"
75+ >
76+ <div class =" flex flex-col gap-1" >
77+ <div class =" font-semibold text-gray-700 dark:text-gray-200" >{{ __('Merge (Recommended)') }}</div >
78+ <div class =" text-sm text-gray-600 dark:text-gray-300" >{{ __('Add this preset as an additional schema alongside your existing ones') }}</div >
79+ </div >
80+ </button >
81+
82+ <button
83+ @click =" handleAction('override')"
84+ class =" border border-gray-200 dark:border-gray-700 rounded-md p-4 text-left cursor-pointer transition-all duration-200 bg-white dark:bg-gray-800 w-full hover:border-amber-500 hover:shadow-md hover:shadow-amber-500/10 dark:hover:border-amber-400"
85+ >
86+ <div class =" flex flex-col gap-1" >
87+ <div class =" font-semibold text-gray-700 dark:text-gray-200" >{{ __('Override') }}</div >
88+ <div class =" text-sm text-gray-600 dark:text-gray-300" >{{ __('Replace all existing schemas with this preset') }}</div >
89+ </div >
90+ </button >
91+ </div >
92+ </div >
93+
94+ <div v-else class =" no-existing-schemas" >
95+ <p class =" text-gray-600 dark:text-gray-300 mb-4" >{{ __('This preset will be added as your first schema.') }}</p >
96+ <button
97+ @click =" handleAction('add')"
98+ class =" px-6 py-3 bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 text-white border-0 rounded cursor-pointer font-medium transition-all duration-200 w-full"
99+ >
100+ {{ __('Add Preset') }}
101+ </button >
102+ </div >
103+ </div >
104+ </div >
105+
106+ <div class =" px-6 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end flex-shrink-0" >
107+ <button
108+ @click =" goBack"
109+ v-if =" selectedPreset"
110+ class =" mr-2 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 cursor-pointer transition-all duration-200 hover:bg-gray-50 dark:hover:bg-gray-600 text-sm"
111+ >
112+ {{ __('Back') }}
113+ </button >
114+ <button
115+ @click =" close"
116+ class =" px-3 py-2 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-200 cursor-pointer transition-all duration-200 hover:bg-gray-50 dark:hover:bg-gray-600 text-sm"
117+ >
118+ {{ __('Cancel') }}
119+ </button >
120+ </div >
121+ </div >
122+ </div >
123+ </template >
124+
125+ <script >
126+ export default {
127+ name: ' PresetModal' ,
128+
129+ props: {
130+ visible: {
131+ type: Boolean ,
132+ default: false
133+ },
134+ presets: {
135+ type: Array ,
136+ default : () => []
137+ },
138+ hasExistingSchemas: {
139+ type: Boolean ,
140+ default: false
141+ }
142+ },
143+
144+ data () {
145+ return {
146+ selectedPreset: null
147+ }
148+ },
149+
150+ watch: {
151+ visible: {
152+ immediate: true ,
153+ handler (newVal ) {
154+ if (newVal) {
155+ this .lockBodyScroll ();
156+ } else {
157+ this .unlockBodyScroll ();
158+ this .selectedPreset = null ;
159+ }
160+ }
161+ }
162+ },
163+
164+ beforeDestroy () {
165+ this .unlockBodyScroll ();
166+ },
167+
168+ methods: {
169+ lockBodyScroll () {
170+ document .body .style .overflow = ' hidden' ;
171+ },
172+
173+ unlockBodyScroll () {
174+ document .body .style .overflow = ' ' ;
175+ },
176+
177+ close () {
178+ this .selectedPreset = null ;
179+ this .$emit (' close' );
180+ },
181+
182+ selectPreset (preset ) {
183+ this .selectedPreset = preset;
184+ },
185+
186+ goBack () {
187+ this .selectedPreset = null ;
188+ },
189+
190+ handleAction (action ) {
191+ this .$emit (' preset-selected' , {
192+ preset: this .selectedPreset ,
193+ action: action
194+ });
195+ this .close ();
196+ }
197+ }
198+ }
199+ </script >
0 commit comments