@fy-/fws-vue 2.3.36 → 2.3.37

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.
@@ -72,72 +72,98 @@ async function patchUser() {
72
72
  </script>
73
73
 
74
74
  <template>
75
- <form @submit.prevent="patchUser">
76
- <DefaultInput
77
- id="firstnameFWS"
78
- v-model="state.userData.Firstname"
79
- class="mb-4"
80
- type="text"
81
- :label="$t('fws_firstname_label')"
82
- :help="$t('fws_firstname_help')"
83
- :error-vuelidate="v$.userData.Firstname.$errors"
84
- />
85
- <DefaultInput
86
- id="lastnameFWS"
87
- v-model="state.userData.Lastname"
88
- class="mb-4"
89
- type="text"
90
- :label="$t('fws_lastname_label')"
91
- :help="$t('fws_lastname_help')"
92
- :error-vuelidate="v$.userData.Lastname.$errors"
93
- />
94
- <DefaultInput
95
- id="phoneFWS"
96
- v-model="state.userData.Phone"
97
- class="mb-4"
98
- type="text"
99
- :label="$t('fws_phone_label')"
100
- :help="$t('fws_phone_help')"
101
- :error-vuelidate="v$.userData.Phone.$errors"
102
- />
103
- <DefaultInput
104
- v-if="!userData?.AcceptedTerms"
105
- id="acceptedTermsFWS"
106
- v-model:checkbox-value="state.userData.AcceptedTerms"
107
- type="toggle"
108
- :label="$t('fws_accepted_terms_label')"
109
- :help="$t('fws_accepted_terms_help')"
110
- :error-vuelidate="v$.userData.AcceptedTerms.$errors"
111
- />
112
- <DefaultInput
113
- id="enabledNotificationsFWS"
114
- v-model:checkbox-value="state.userData.EnabledNotifications"
115
- type="toggle"
116
- :label="$t('fws_enabled_notifications_label')"
117
- :help="$t('fws_enabled_notifications_help')"
118
- :error-vuelidate="v$.userData.EnabledNotifications.$errors"
119
- />
120
- <DefaultInput
121
- id="enabledEmailsFWS"
122
- v-model:checkbox-value="state.userData.EnabledEmails"
123
- type="toggle"
124
- :label="$t('fws_enabled_emails_label')"
125
- :help="$t('fws_enabled_emails_help')"
126
- :error-vuelidate="v$.userData.EnabledEmails.$errors"
127
- />
128
- <DefaultInput
129
- id="enabledTrainingFromMyDataFWS"
130
- v-model:checkbox-value="state.userData.EnabledTrainingFromMyData"
131
- type="toggle"
132
- :label="$t('fws_enabled_training_from_my_data_label')"
133
- :help="$t('fws_enabled_training_from_my_data_help')"
134
- :error-vuelidate="v$.userData.EnabledTrainingFromMyData.$errors"
135
- />
75
+ <form class="space-y-4" @submit.prevent="patchUser">
76
+ <div class="bg-white dark:bg-fv-neutral-800 p-4 sm:p-6 rounded-lg shadow-sm border border-fv-neutral-200 dark:border-fv-neutral-700">
77
+ <h3 class="text-lg font-semibold text-fv-neutral-900 dark:text-white mb-4 sm:mb-5 pb-2 border-b border-fv-neutral-200 dark:border-fv-neutral-700">
78
+ {{ $t('fws_personal_data_title') || $t('fws_personal_information') }}
79
+ </h3>
136
80
 
137
- <div class="flex">
138
- <button type="submit" class="btn defaults primary">
139
- {{ $t("fws_save_user_cta") }}
140
- </button>
81
+ <!-- Personal Information Section -->
82
+ <div class="grid gap-4 md:grid-cols-2 mb-4 sm:mb-6">
83
+ <DefaultInput
84
+ id="firstnameFWS"
85
+ v-model="state.userData.Firstname"
86
+ type="text"
87
+ :label="$t('fws_firstname_label')"
88
+ :help="$t('fws_firstname_help')"
89
+ :error-vuelidate="v$.userData.Firstname.$errors"
90
+ />
91
+ <DefaultInput
92
+ id="lastnameFWS"
93
+ v-model="state.userData.Lastname"
94
+ type="text"
95
+ :label="$t('fws_lastname_label')"
96
+ :help="$t('fws_lastname_help')"
97
+ :error-vuelidate="v$.userData.Lastname.$errors"
98
+ />
99
+ <DefaultInput
100
+ id="phoneFWS"
101
+ v-model="state.userData.Phone"
102
+ type="text"
103
+ :label="$t('fws_phone_label')"
104
+ :help="$t('fws_phone_help')"
105
+ :error-vuelidate="v$.userData.Phone.$errors"
106
+ />
107
+ </div>
108
+
109
+ <!-- Terms & Preferences -->
110
+ <div class="pt-3 sm:pt-4 border-t border-fv-neutral-200 dark:border-fv-neutral-700">
111
+ <h4 class="font-medium text-fv-neutral-800 dark:text-white mb-2 sm:mb-3">
112
+ {{ $t('fws_preferences_and_settings') }}
113
+ </h4>
114
+
115
+ <div class="grid gap-2 sm:gap-3 p-1 sm:p-2">
116
+ <DefaultInput
117
+ v-if="!userData?.AcceptedTerms"
118
+ id="acceptedTermsFWS"
119
+ v-model:checkbox-value="state.userData.AcceptedTerms"
120
+ type="toggle"
121
+ :label="$t('fws_accepted_terms_label')"
122
+ :help="$t('fws_accepted_terms_help')"
123
+ :error-vuelidate="v$.userData.AcceptedTerms.$errors"
124
+ />
125
+
126
+ <div class="grid gap-3 md:grid-cols-2 my-1">
127
+ <DefaultInput
128
+ id="enabledNotificationsFWS"
129
+ v-model:checkbox-value="state.userData.EnabledNotifications"
130
+ type="toggle"
131
+ :label="$t('fws_enabled_notifications_label')"
132
+ :help="$t('fws_enabled_notifications_help')"
133
+ :error-vuelidate="v$.userData.EnabledNotifications.$errors"
134
+ />
135
+ <DefaultInput
136
+ id="enabledEmailsFWS"
137
+ v-model:checkbox-value="state.userData.EnabledEmails"
138
+ type="toggle"
139
+ :label="$t('fws_enabled_emails_label')"
140
+ :help="$t('fws_enabled_emails_help')"
141
+ :error-vuelidate="v$.userData.EnabledEmails.$errors"
142
+ />
143
+ </div>
144
+
145
+ <div class="py-2 px-2 sm:px-3 my-2 bg-fv-neutral-50 dark:bg-fv-neutral-700/30 rounded-lg border border-fv-neutral-200 dark:border-fv-neutral-700">
146
+ <DefaultInput
147
+ id="enabledTrainingFromMyDataFWS"
148
+ v-model:checkbox-value="state.userData.EnabledTrainingFromMyData"
149
+ type="toggle"
150
+ :label="$t('fws_enabled_training_from_my_data_label')"
151
+ :help="$t('fws_enabled_training_from_my_data_help')"
152
+ :error-vuelidate="v$.userData.EnabledTrainingFromMyData.$errors"
153
+ />
154
+ </div>
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Save Button -->
159
+ <div class="flex justify-end mt-6">
160
+ <button type="submit" class="btn defaults primary flex items-center gap-2">
161
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
162
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
163
+ </svg>
164
+ {{ $t("fws_save_user_cta") }}
165
+ </button>
166
+ </div>
141
167
  </div>
142
168
  </form>
143
169
  </template>
@@ -81,93 +81,148 @@ onMounted(() => {
81
81
 
82
82
  <template>
83
83
  <div class="flex flex-col gap-3">
84
+ <!-- Provider Selection Modal -->
84
85
  <DefaultModal id="providers" :title="$t('providers_modal_title')">
85
- <template v-for="provider in providersData" :key="provider.UUID">
86
- <div
87
- v-if="!usedProviders[provider.UUID]"
88
- class="flex items-center gap-3"
89
- >
90
- <button
91
- class="flex border border-fv-neutral-300 dark:border-fv-neutral-700 shadow items-center gap-2 justify-start btn neutral defaults w-full mx-auto !font-semibold"
92
- :style="`background: ${
93
- provider.Data.Button.button['background-color']
94
- }; color: ${$getContrastingTextColor(
95
- provider.Data.Button.button['background-color'],
96
- )}`"
97
- @click="
98
- () => {
99
- getOAuth2Redirect(provider.UUID);
100
- }
101
- "
86
+ <div class="grid gap-4 p-1">
87
+ <template v-for="provider in providersData" :key="provider.UUID">
88
+ <div
89
+ v-if="!usedProviders[provider.UUID]"
90
+ class="flex items-center"
102
91
  >
103
- <img
104
- :key="`${provider.Data.Button.label}oauth`"
105
- class="h-12 w-12 block p-2 mr-3"
106
- :alt="provider.Data.Button.info.Name"
107
- :src="provider.Data.Button.button.logo"
92
+ <button
93
+ class="flex border border-fv-neutral-300 dark:border-fv-neutral-700 rounded-lg shadow-sm hover:shadow items-center gap-2 justify-start w-full mx-auto !font-medium p-3 transition-all duration-200"
94
+ :style="`background: ${
95
+ provider.Data.Button.button['background-color']
96
+ }; color: ${$getContrastingTextColor(
97
+ provider.Data.Button.button['background-color'],
98
+ )}`"
99
+ @click="
100
+ () => {
101
+ getOAuth2Redirect(provider.UUID);
102
+ }
103
+ "
108
104
  >
109
- <div>
110
- {{
111
- $t("user_flow_signin_with", {
112
- provider: provider.Data.Button.name,
113
- })
114
- }}
115
- </div>
116
- </button>
117
- </div>
118
- </template>
105
+ <img
106
+ :key="`${provider.Data.Button.label}oauth`"
107
+ class="h-10 w-10 block p-1.5 mr-3 rounded"
108
+ :alt="provider.Data.Button.info.Name"
109
+ :src="provider.Data.Button.button.logo"
110
+ >
111
+ <div class="text-base">
112
+ {{
113
+ $t("user_flow_signin_with", {
114
+ provider: provider.Data.Button.name,
115
+ })
116
+ }}
117
+ </div>
118
+ </button>
119
+ </div>
120
+ </template>
121
+ </div>
119
122
  </DefaultModal>
120
- <h2 class="h3 flex items-center justify-between">
121
- <span>{{ $t("oauth2_providers_title") }}</span>
122
- <button
123
- class="btn primary medium !py-1 !px-3"
124
- @click="
125
- () => {
126
- $eventBus.emit('providersModal', true);
127
- }
128
- "
123
+
124
+ <!-- Main Container -->
125
+ <div class="bg-white dark:bg-fv-neutral-800 rounded-lg shadow-sm border border-fv-neutral-200 dark:border-fv-neutral-700 p-4 sm:p-6">
126
+ <!-- Header -->
127
+ <div class="flex items-center justify-between mb-4 sm:mb-6 pb-2 sm:pb-3 border-b border-fv-neutral-200 dark:border-fv-neutral-700">
128
+ <h2 class="text-lg font-semibold text-fv-neutral-900 dark:text-white">
129
+ {{ $t("oauth2_providers_title") }}
130
+ </h2>
131
+ <button
132
+ class="btn primary small flex items-center gap-2"
133
+ @click="
134
+ () => {
135
+ $eventBus.emit('providersModal', true);
136
+ }
137
+ "
138
+ >
139
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
140
+ <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
141
+ </svg>
142
+ {{ $t("add_oauth2_con_cta") }}
143
+ </button>
144
+ </div>
145
+
146
+ <!-- Error Message -->
147
+ <div
148
+ v-if="$route.query.error && $route.query.error === 'user_oauth2_connection_exists'"
149
+ class="mb-3 sm:mb-4 p-2 sm:p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg"
129
150
  >
130
- {{ $t("add_oauth2_con_cta") }}
131
- </button>
132
- </h2>
133
- <p
134
- v-if="
135
- $route.query.error
136
- && $route.query.error === 'user_oauth2_connection_exists'
137
- "
138
- class="text-red-900 dark:text-red-300 text-sm bg-red-200/[.2] dark:bg-red-900/[.2] p-2 rounded shadow"
139
- >
140
- {{ $t("oauth2_error_user_oauth2_connection_exists") }}
141
- </p>
142
- <div v-if="data && data.length === 0">
143
- <p>{{ $t("providers_empty") }}</p>
144
- </div>
145
- <div
146
- v-for="provider in data"
147
- :key="provider.ProviderUUID"
148
- class="flex items-center gap-3"
149
- >
150
- <img
151
- :src="provider.Provider.Button.button.logo"
152
- class="w-14 h-14 p-1 rounded-full"
153
- :style="`background-color: ${provider.Provider.Button.button['background-color']}`"
151
+ <div class="flex items-start">
152
+ <svg class="w-5 h-5 text-red-600 dark:text-red-400 mt-0.5 mr-2 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
153
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
154
+ </svg>
155
+ <p class="text-sm text-red-700 dark:text-red-300">
156
+ {{ $t("oauth2_error_user_oauth2_connection_exists") }}
157
+ </p>
158
+ </div>
159
+ </div>
160
+
161
+ <!-- Empty State -->
162
+ <div
163
+ v-if="data && data.length === 0"
164
+ class="py-6 sm:py-8 px-3 sm:px-4 text-center bg-fv-neutral-50 dark:bg-fv-neutral-700/30 rounded-lg border border-fv-neutral-200 dark:border-fv-neutral-700"
154
165
  >
155
- <div>
156
- <h3 class="text-xl">
157
- {{ provider.Provider.Button.name }}
158
- <small class="text-xs">({{ provider.ServiceID }})</small>
159
- </h3>
160
- <div class="flex gap-2 mt-1">
161
- <button
162
- class="btn danger small"
163
- @click="
164
- () => {
165
- deleteOAuth2Connection(provider.ProviderUUID);
166
- }
167
- "
168
- >
169
- {{ $t("remove_oauth2_con_cta") }}
170
- </button>
166
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto text-fv-neutral-400 dark:text-fv-neutral-500 mb-3" viewBox="0 0 20 20" fill="currentColor">
167
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
168
+ </svg>
169
+ <p class="text-fv-neutral-700 dark:text-fv-neutral-300">
170
+ {{ $t("providers_empty") }}
171
+ </p>
172
+ <button
173
+ class="btn primary small mt-3"
174
+ @click="
175
+ () => {
176
+ $eventBus.emit('providersModal', true);
177
+ }
178
+ "
179
+ >
180
+ {{ $t("add_oauth2_con_cta") }}
181
+ </button>
182
+ </div>
183
+
184
+ <!-- Connected Providers List -->
185
+ <div v-else class="grid gap-3 sm:gap-4">
186
+ <div
187
+ v-for="provider in data"
188
+ :key="provider.ProviderUUID"
189
+ class="flex items-center p-3 sm:p-4 bg-fv-neutral-50 dark:bg-fv-neutral-700/30 rounded-lg border border-fv-neutral-200 dark:border-fv-neutral-700 transition-all duration-200 hover:shadow-sm"
190
+ >
191
+ <div class="flex-shrink-0 mr-4">
192
+ <div
193
+ class="w-14 h-14 rounded-full flex items-center justify-center p-0.5"
194
+ :style="`background-color: ${provider.Provider.Button.button['background-color']}`"
195
+ >
196
+ <img
197
+ :src="provider.Provider.Button.button.logo"
198
+ class="w-10 h-10 object-contain"
199
+ :alt="provider.Provider.Button.name"
200
+ >
201
+ </div>
202
+ </div>
203
+ <div class="flex-1 min-w-0">
204
+ <h3 class="text-lg font-medium text-fv-neutral-900 dark:text-white truncate">
205
+ {{ provider.Provider.Button.name }}
206
+ </h3>
207
+ <p class="text-sm text-fv-neutral-500 dark:text-fv-neutral-400 truncate">
208
+ {{ provider.ServiceID }}
209
+ </p>
210
+ </div>
211
+ <div class="ml-4">
212
+ <button
213
+ class="btn danger small flex items-center gap-1.5"
214
+ @click="
215
+ () => {
216
+ deleteOAuth2Connection(provider.ProviderUUID);
217
+ }
218
+ "
219
+ >
220
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
221
+ <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
222
+ </svg>
223
+ {{ $t("remove_oauth2_con_cta") }}
224
+ </button>
225
+ </div>
171
226
  </div>
172
227
  </div>
173
228
  </div>
@@ -160,118 +160,176 @@ function selectFile(e: Event) {
160
160
  </script>
161
161
 
162
162
  <template>
163
- <form @submit.prevent="patchUser">
164
- <DefaultInput
165
- id="usernameFWS"
166
- v-model="state.userData.Username"
167
- class="mb-4"
168
- type="text"
169
- :label="$t('fws_username_label')"
170
- :help="$t('fws_username_help')"
171
- :error-vuelidate="v$.userData.Username.$errors"
172
- :disabled="userData?.UserProfile?.HasUsernameAndSlug ? true : false"
173
- />
174
- <div class="flex gap-2 items-center mb-4">
175
- <img
176
- v-if="userData?.UserProfile?.AvatarUUID"
177
- :src="`${imageDomain}/${userData?.UserProfile?.AvatarUUID}?vars=format=png:resize=100x100`"
178
- class="w-16 h-16 rounded-full flex-0 shrink-0 grow-0"
179
- >
180
- <div class="flex-1">
181
- <label
182
- class="block text-sm font-medium mb-2 text-neutral-900 dark:text-white"
183
- for="file_input"
184
- >{{ $t("fws_upload_av_label") }}</label>
185
- <input
186
- ref="uploadInput"
187
- class="block text-sm w-full text-neutral-900 border border-neutral-300 rounded-lg cursor-pointer bg-neutral-50 dark:text-neutral-400 focus:outline-none dark:bg-neutral-700 dark:border-neutral-600 dark:placeholder-neutral-400"
188
- type="file"
189
- accept="image/jpg, image/jpeg, image/png, image/gif"
190
- @change="selectFile"
191
- >
163
+ <form class="space-y-4" @submit.prevent="patchUser">
164
+ <div class="bg-white dark:bg-fv-neutral-800 p-4 sm:p-6 rounded-lg shadow-sm border border-fv-neutral-200 dark:border-fv-neutral-700">
165
+ <h3 class="text-lg font-semibold text-fv-neutral-900 dark:text-white mb-4 pb-2 border-b border-fv-neutral-200 dark:border-fv-neutral-700">
166
+ {{ $t('fws_profile_heading') || $t('fws_your_profile') }}
167
+ </h3>
168
+
169
+ <!-- Username and Avatar Section -->
170
+ <div class="grid md:grid-cols-2 gap-4 sm:gap-6 mb-4 sm:mb-6">
171
+ <!-- Avatar Upload -->
172
+ <div class="flex flex-col">
173
+ <h4 class="font-medium text-fv-neutral-800 dark:text-white text-sm mb-3">
174
+ {{ $t("fws_profile_image") }}
175
+ </h4>
176
+ <div class="flex items-center gap-3 sm:gap-4">
177
+ <div class="relative group">
178
+ <img
179
+ v-if="userData?.UserProfile?.AvatarUUID"
180
+ :src="`${imageDomain}/${userData?.UserProfile?.AvatarUUID}?vars=format=png:resize=100x100`"
181
+ class="w-20 h-20 rounded-full object-cover border-2 border-fv-neutral-200 dark:border-fv-neutral-700 shadow-sm"
182
+ alt="Profile Avatar"
183
+ >
184
+ <div v-else class="w-20 h-20 rounded-full bg-fv-neutral-200 dark:bg-fv-neutral-700 flex items-center justify-center">
185
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-fv-neutral-400 dark:text-fv-neutral-500" viewBox="0 0 20 20" fill="currentColor">
186
+ <path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd" />
187
+ </svg>
188
+ </div>
189
+ </div>
190
+
191
+ <div class="flex-1">
192
+ <label
193
+ class="block text-sm font-medium mb-2 text-fv-neutral-800 dark:text-white"
194
+ for="file_input"
195
+ >{{ $t("fws_upload_av_label") }}</label>
196
+ <div class="relative">
197
+ <input
198
+ id="file_input"
199
+ ref="uploadInput"
200
+ class="block text-sm w-full text-fv-neutral-700 border border-fv-neutral-300 rounded-lg cursor-pointer bg-fv-neutral-50 dark:text-fv-neutral-400 focus:outline-none dark:bg-fv-neutral-700 dark:border-fv-neutral-600 file:mr-4 file:py-2 file:px-4 file:border-0 file:text-sm file:font-medium file:bg-fv-primary-50 file:text-fv-primary-600 dark:file:bg-fv-primary-900 dark:file:text-fv-primary-300 hover:file:bg-fv-primary-100 dark:hover:file:bg-fv-primary-800"
201
+ type="file"
202
+ accept="image/jpg, image/jpeg, image/png, image/gif"
203
+ @change="selectFile"
204
+ >
205
+ </div>
206
+ <p class="mt-1 text-xs text-fv-neutral-500 dark:text-fv-neutral-400">
207
+ {{ $t("fws_upload_av_help") || "JPG, JPEG, PNG or GIF (max 2MB)" }}
208
+ </p>
209
+ </div>
210
+ </div>
211
+ </div>
212
+
213
+ <!-- Username -->
214
+ <div class="flex flex-col justify-center">
215
+ <DefaultInput
216
+ id="usernameFWS"
217
+ v-model="state.userData.Username"
218
+ type="text"
219
+ :label="$t('fws_username_label')"
220
+ :help="$t('fws_username_help')"
221
+ :error-vuelidate="v$.userData.Username.$errors"
222
+ :disabled="userData?.UserProfile?.HasUsernameAndSlug ? true : false"
223
+ />
224
+ </div>
192
225
  </div>
193
- </div>
194
- <DefaultModal id="avCrop" :title="$t('fws_crop_av_title')">
195
- <button class="btn defaults primary" @click="getCropResult">
196
- {{ $t("fws_crop_av_cta") }}
197
- </button>
198
- <div class="max-h-[80vh]">
199
- <VuePictureCropper
200
- :box-style="{
201
- width: 'auto',
202
- height: 'auto',
203
- backgroundColor: '#f8f8f8',
204
- margin: 'auto',
205
- }"
206
- :img="pic"
207
- :options="{
208
- viewMode: 1,
209
- dragMode: 'crop',
210
- aspectRatio: 1 / 1,
211
- }"
212
- class="max-h-[70vh] w-full"
226
+
227
+ <!-- Cropper Modal -->
228
+ <DefaultModal id="avCrop" :title="$t('fws_crop_av_title')">
229
+ <div class="flex flex-col gap-4">
230
+ <div class="max-h-[70vh] overflow-hidden rounded-lg border border-fv-neutral-200 dark:border-fv-neutral-700">
231
+ <VuePictureCropper
232
+ :box-style="{
233
+ width: 'auto',
234
+ height: 'auto',
235
+ backgroundColor: '#f8f8f8',
236
+ margin: 'auto',
237
+ }"
238
+ :img="pic"
239
+ :options="{
240
+ viewMode: 1,
241
+ dragMode: 'crop',
242
+ aspectRatio: 1 / 1,
243
+ }"
244
+ class="max-h-[70vh] w-full"
245
+ />
246
+ </div>
247
+ <button class="btn defaults primary self-end" @click="getCropResult">
248
+ {{ $t("fws_crop_av_cta") }}
249
+ </button>
250
+ </div>
251
+ </DefaultModal>
252
+
253
+ <!-- Profile Information -->
254
+ <div class="grid md:grid-cols-2 gap-x-4 sm:gap-x-6 gap-y-3 sm:gap-y-4 mb-4 sm:mb-6">
255
+ <DefaultInput
256
+ id="genderFWS"
257
+ v-model="state.userData.Gender"
258
+ type="select"
259
+ :options="[
260
+ ['female', $t('fws_persona_phys_appearance_opt_female')],
261
+ ['male', $t('fws_persona_phys_appearance_opt_male')],
262
+ ['non-binary', $t('fws_persona_phys_appearance_opt_non_binary')],
263
+ ]"
264
+ :label="$t('fws_gender_label')"
265
+ :error-vuelidate="v$.userData.Gender.$errors"
266
+ />
267
+
268
+ <DefaultInput
269
+ id="birthdateFWS"
270
+ v-model="state.userData.Birthdate"
271
+ type="datepicker"
272
+ :disable-dates-under18="true"
273
+ :label="$t('fws_birthdate_label')"
274
+ :error-vuelidate="v$.userData.Birthdate.$errors"
275
+ />
276
+ </div>
277
+
278
+ <!-- Bio -->
279
+ <div class="mb-4 sm:mb-6">
280
+ <DefaultInput
281
+ id="bioFWS"
282
+ v-model="state.userData.Bio"
283
+ type="textarea"
284
+ :label="$t('fws_bio_label')"
285
+ :error-vuelidate="v$.userData.Bio.$errors"
286
+ :dp-options="{ counterMax: 1000 }"
213
287
  />
214
288
  </div>
215
- </DefaultModal>
216
- <DefaultInput
217
- id="genderFWS"
218
- v-model="state.userData.Gender"
219
- class="mb-4"
220
- type="select"
221
- :options="[
222
- ['female', $t('fws_persona_phys_appearance_opt_female')],
223
- ['male', $t('fws_persona_phys_appearance_opt_male')],
224
- ['non-binary', $t('fws_persona_phys_appearance_opt_non_binary')],
225
- ]"
226
- :label="$t('fws_gender_label')"
227
- :error-vuelidate="v$.userData.Gender.$errors"
228
- />
229
- <DefaultInput
230
- id="birthdateFWS"
231
- v-model="state.userData.Birthdate"
232
- class="mb-4"
233
- type="datepicker"
234
- :disable-dates-under18="true"
235
- :label="$t('fws_birthdate_label')"
236
- :error-vuelidate="v$.userData.Birthdate.$errors"
237
- />
238
- <DefaultInput
239
- id="bioFWS"
240
- v-model="state.userData.Bio"
241
- class="mb-4"
242
- type="textarea"
243
- :label="$t('fws_bio_label')"
244
- :error-vuelidate="v$.userData.Bio.$errors"
245
- />
246
- <template v-if="!hidePublic">
247
- <DefaultInput
248
- v-if="!hideGender"
249
- id="publicGenderFWS"
250
- v-model:checkbox-value="state.userData.PublicGender"
251
- type="toggle"
252
- :label="$t('fws_public_gender')"
253
- :error-vuelidate="v$.userData.PublicGender.$errors"
254
- />
255
- <DefaultInput
256
- id="publicBioFWS"
257
- v-model:checkbox-value="state.userData.PublicBio"
258
- type="toggle"
259
- :label="$t('fws_public_bio')"
260
- :error-vuelidate="v$.userData.PublicBio.$errors"
261
- />
262
- <DefaultInput
263
- v-if="!hideBirthdate"
264
- id="publicBirthdateFWS"
265
- v-model:checkbox-value="state.userData.PublicBirthdate"
266
- type="toggle"
267
- :label="$t('fws_public_birthdate')"
268
- :error-vuelidate="v$.userData.PublicBirthdate.$errors"
269
- />
270
- </template>
271
- <div class="flex">
272
- <button type="submit" class="btn defaults primary">
273
- {{ $t("fws_save_user_cta") }}
274
- </button>
289
+
290
+ <!-- Privacy Settings -->
291
+ <template v-if="!hidePublic">
292
+ <div class="pt-3 sm:pt-4 border-t border-fv-neutral-200 dark:border-fv-neutral-700 mb-3 sm:mb-4">
293
+ <h4 class="font-medium text-fv-neutral-800 dark:text-white mb-3">
294
+ {{ $t('fws_privacy_settings') }}
295
+ </h4>
296
+ <div class="grid gap-2">
297
+ <DefaultInput
298
+ v-if="!hideGender"
299
+ id="publicGenderFWS"
300
+ v-model:checkbox-value="state.userData.PublicGender"
301
+ type="toggle"
302
+ :label="$t('fws_public_gender')"
303
+ :error-vuelidate="v$.userData.PublicGender.$errors"
304
+ />
305
+ <DefaultInput
306
+ id="publicBioFWS"
307
+ v-model:checkbox-value="state.userData.PublicBio"
308
+ type="toggle"
309
+ :label="$t('fws_public_bio')"
310
+ :error-vuelidate="v$.userData.PublicBio.$errors"
311
+ />
312
+ <DefaultInput
313
+ v-if="!hideBirthdate"
314
+ id="publicBirthdateFWS"
315
+ v-model:checkbox-value="state.userData.PublicBirthdate"
316
+ type="toggle"
317
+ :label="$t('fws_public_birthdate')"
318
+ :error-vuelidate="v$.userData.PublicBirthdate.$errors"
319
+ />
320
+ </div>
321
+ </div>
322
+ </template>
323
+
324
+ <!-- Save Button -->
325
+ <div class="flex justify-end pt-2">
326
+ <button type="submit" class="btn defaults primary flex items-center gap-2">
327
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
328
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
329
+ </svg>
330
+ {{ $t("fws_save_user_cta") }}
331
+ </button>
332
+ </div>
275
333
  </div>
276
334
  </form>
277
335
  </template>
@@ -110,57 +110,68 @@ async function patchUser() {
110
110
  </script>
111
111
 
112
112
  <template>
113
- <form @submit.prevent="patchUser">
114
- <DefaultInput
115
- id="usernameFWS"
116
- v-model="state.userData.Username"
117
- class="mb-4"
118
- type="text"
119
- :label="$t('fws_username_label')"
120
- :help="$t('fws_username_help')"
121
- :error-vuelidate="v$.userData.Username.$errors"
122
- :disabled="userData?.UserProfile?.HasUsernameAndSlug ? true : false"
123
- />
124
- <DefaultInput
125
- id="birthdateFWS"
126
- v-model="state.userData.Birthdate"
127
- class="mb-4"
128
- :disable-dates-under18="true"
129
- type="datepicker"
130
- :label="$t('fws_birthdate_label')"
131
- :error-vuelidate="v$.userData.Birthdate.$errors"
132
- />
113
+ <form class="space-y-4" @submit.prevent="patchUser">
114
+ <div class="bg-white dark:bg-fv-neutral-800 p-4 sm:p-6 rounded-lg shadow-sm border border-fv-neutral-200 dark:border-fv-neutral-700">
115
+ <h3 class="text-lg font-semibold text-fv-neutral-900 dark:text-white mb-4 pb-2 border-b border-fv-neutral-200 dark:border-fv-neutral-700">
116
+ {{ $t('fws_user_profile_title') || $t('fws_profile_settings') }}
117
+ </h3>
133
118
 
134
- <DefaultInput
135
- id="genderFWS"
136
- v-model="state.userData.Gender"
137
- class="mb-4"
138
- type="select"
139
- :options="[
140
- ['female', $t('fws_persona_phys_appearance_opt_female')],
141
- ['male', $t('fws_persona_phys_appearance_opt_male')],
142
- ['non-binary', $t('fws_persona_phys_appearance_opt_non_binary')],
143
- ]"
144
- :label="$t('fws_gender_label')"
145
- :error-vuelidate="v$.userData.Gender.$errors"
146
- />
119
+ <div class="grid gap-4">
120
+ <DefaultInput
121
+ id="usernameFWS"
122
+ v-model="state.userData.Username"
123
+ type="text"
124
+ :label="$t('fws_username_label')"
125
+ :help="$t('fws_username_help')"
126
+ :error-vuelidate="v$.userData.Username.$errors"
127
+ :disabled="userData?.UserProfile?.HasUsernameAndSlug ? true : false"
128
+ />
147
129
 
148
- <DefaultInput
149
- id="acceptedTermsFWS"
150
- v-model:checkbox-value="state.userData.AcceptedTerms"
151
- type="toggle"
152
- :label="$t('fws_accepted_terms_label')"
153
- :help="$t('fws_accepted_terms_help')"
154
- :error-vuelidate="v$.userData.AcceptedTerms.$errors"
155
- />
156
- <p v-if="props.termsText" class="terms-box">
157
- {{ props.termsText }}
158
- </p>
130
+ <DefaultInput
131
+ id="birthdateFWS"
132
+ v-model="state.userData.Birthdate"
133
+ :disable-dates-under18="true"
134
+ type="datepicker"
135
+ :label="$t('fws_birthdate_label')"
136
+ :error-vuelidate="v$.userData.Birthdate.$errors"
137
+ />
159
138
 
160
- <div class="flex">
161
- <button type="submit" class="btn defaults primary">
162
- {{ $t("fws_save_user_cta") }}
163
- </button>
139
+ <DefaultInput
140
+ id="genderFWS"
141
+ v-model="state.userData.Gender"
142
+ type="select"
143
+ :options="[
144
+ ['female', $t('fws_persona_phys_appearance_opt_female')],
145
+ ['male', $t('fws_persona_phys_appearance_opt_male')],
146
+ ['non-binary', $t('fws_persona_phys_appearance_opt_non_binary')],
147
+ ]"
148
+ :label="$t('fws_gender_label')"
149
+ :error-vuelidate="v$.userData.Gender.$errors"
150
+ />
151
+
152
+ <div class="mt-2 pt-3 border-t border-fv-neutral-200 dark:border-fv-neutral-700">
153
+ <DefaultInput
154
+ id="acceptedTermsFWS"
155
+ v-model:checkbox-value="state.userData.AcceptedTerms"
156
+ type="toggle"
157
+ :label="$t('fws_accepted_terms_label')"
158
+ :help="$t('fws_accepted_terms_help')"
159
+ :error-vuelidate="v$.userData.AcceptedTerms.$errors"
160
+ />
161
+ <p v-if="props.termsText" class="mt-2 p-2 sm:p-3 text-sm bg-fv-neutral-50 dark:bg-fv-neutral-700 rounded border border-fv-neutral-200 dark:border-fv-neutral-600 text-fv-neutral-700 dark:text-fv-neutral-300">
162
+ {{ props.termsText }}
163
+ </p>
164
+ </div>
165
+ </div>
166
+
167
+ <div class="mt-6 flex justify-end">
168
+ <button type="submit" class="btn defaults primary flex items-center gap-2">
169
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
170
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
171
+ </svg>
172
+ {{ $t("fws_save_user_cta") }}
173
+ </button>
174
+ </div>
164
175
  </div>
165
176
  </form>
166
177
  </template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fy-/fws-vue",
3
- "version": "2.3.36",
3
+ "version": "2.3.37",
4
4
  "author": "Florian 'Fy' Gasquez <m@fy.to>",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/fy-to/FWJS#readme",