Skip to content

Commit bfa4e41

Browse files
authored
feat: add polish and features to localization modal (#959)
1 parent 630a27d commit bfa4e41

14 files changed

Lines changed: 954 additions & 247 deletions

File tree

.changeset/empty-moles-thank.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@blinkk/root-cms': patch
3+
---
4+
5+
feat: add polish and features to localization modal

packages/root-cms/ui/components/DocEditor/DocEditor.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ type StatusBarProps = DocEditorProps & {
177177
};
178178

179179
DocEditor.StatusBar = (props: StatusBarProps) => {
180-
const {route} = useLocation();
180+
const {route, query} = useLocation();
181181
const {roles} = useProjectRoles();
182182
const currentUserEmail = window.firebase.user.email || '';
183183
const canPublish = testCanPublish(roles, currentUserEmail);
@@ -212,6 +212,20 @@ DocEditor.StatusBar = (props: StatusBarProps) => {
212212
const publishDocModal = usePublishDocModal({docId: props.docId});
213213
const localizationModal = useLocalizationModal();
214214

215+
const urlLocale = (query.locale as string) || '';
216+
const urlModal = (query.modal as string) || '';
217+
218+
useEffect(() => {
219+
if (urlModal === 'localization' && draft.controller) {
220+
localizationModal.open({
221+
docId: props.docId,
222+
collection: props.collection,
223+
draft: draft.controller,
224+
locale: urlLocale || undefined,
225+
});
226+
}
227+
}, []);
228+
215229
const loading = !data?.sys;
216230
if (loading) {
217231
return null;
@@ -234,13 +248,14 @@ DocEditor.StatusBar = (props: StatusBarProps) => {
234248
color="dark"
235249
size="xs"
236250
leftIcon={<IconPlanet size={16} />}
237-
onClick={() =>
251+
onClick={() => {
238252
localizationModal.open({
239253
docId: props.docId,
240254
collection: props.collection,
241255
draft: draft.controller,
242-
})
243-
}
256+
locale: (query.locale as string) || undefined,
257+
});
258+
}}
244259
>
245260
Localization
246261
</Button>

packages/root-cms/ui/components/EditTranslationsModal/EditTranslationsModal.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,24 @@ export function EditTranslationsModal(
340340
position="left"
341341
>
342342
<ActionIcon
343-
variant="light"
343+
variant="outline"
344344
onClick={generateAiTranslations}
345345
loading={aiGenerating}
346346
disabled={aiGenerating}
347-
size="sm"
347+
sx={{
348+
height: 30,
349+
width: 30,
350+
borderColor: '#ced4da',
351+
}}
348352
>
349353
{aiGenerating ? (
350354
<IconLoader2 size={16} />
351355
) : (
352-
<IconSparkles size={16} />
356+
<IconSparkles
357+
size={16}
358+
fill="currentColor"
359+
stroke={1.5}
360+
/>
353361
)}
354362
</ActionIcon>
355363
</Tooltip>

packages/root-cms/ui/components/LocalizationModal/LocalizationModal.css

Lines changed: 206 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,110 @@
22
padding: 30px 40px;
33
}
44

5+
.mantine-Modal-modal:has(.LocalizationModal__layout) {
6+
padding-bottom: 0;
7+
}
8+
9+
.mantine-Modal-modal:has(.LocalizationModal__layout) .mantine-Modal-header {
10+
transform: translateY(-10px);
11+
}
12+
513
.LocalizationModal__layout {
614
display: grid;
7-
grid-template-columns: 400px 1fr;
15+
grid-template-columns: minmax(auto, 400px) 1fr;
816
margin-top: -20px;
9-
margin-bottom: 20px;
17+
}
18+
19+
@media (max-width: 1024px) {
20+
.LocalizationModal__layout {
21+
grid-template-columns: minmax(auto, 200px) 1fr;
22+
}
1023
}
1124

1225
.LocalizationModal__iconTitle {
1326
display: flex;
1427
align-items: center;
1528
gap: 8px;
29+
white-space: nowrap;
1630
}
1731

1832
.LocalizationModal__locales,
1933
.LocalizationModal__translations {
2034
height: 100%;
2135
min-height: 400px;
22-
padding-top: 30px;
2336
padding-bottom: 30px;
2437
}
2538

2639
.LocalizationModal__locales {
2740
padding-right: 30px;
41+
padding-top: 30px;
2842
}
2943

3044
.LocalizationModal__translations {
3145
border-left: 1px solid var(--color-border);
3246
padding-left: 30px;
33-
margin-right: -30px;
3447
padding-right: 30px;
3548
max-height: 80vh;
3649
overflow: auto;
50+
margin-left: -30px;
51+
margin-right: -21px;
52+
padding-bottom: 0;
53+
display: flex;
54+
flex-direction: column;
55+
justify-content: space-between;
3756
}
3857

3958
.LocalizationModal__translations__header {
4059
display: flex;
4160
justify-content: space-between;
42-
margin-bottom: 30px;
61+
align-items: flex-start;
62+
gap: 12px;
63+
position: sticky;
64+
top: 0;
65+
background: var(--color-background, #fff);
66+
z-index: 10;
67+
padding-top: 8px;
68+
padding-bottom: 10px;
4369
}
4470

4571
.LocalizationModal__translations__header__buttons {
4672
display: flex;
4773
align-items: center;
4874
gap: 8px;
75+
flex-wrap: wrap;
76+
justify-content: flex-end;
4977
}
5078

5179
.LocalizationModal__translations__titleWrap {
5280
display: flex;
5381
align-items: center;
5482
gap: 12px;
83+
flex-wrap: wrap;
84+
min-width: 0;
5585
}
5686

5787
.LocalizationModal__translations__table {
5888
display: flex;
5989
flex-direction: column;
90+
width: 100%;
91+
margin-bottom: 12px;
6092
}
6193

6294
.LocalizationModal__translations__table__row {
6395
display: grid;
6496
grid-template-columns: 1fr 1fr;
97+
min-width: 0;
6598
}
6699

67100
.LocalizationModal__translations__table__row--header {
68101
align-items: center;
102+
position: sticky;
103+
top: 48px;
104+
background: var(--color-background, #fff);
105+
z-index: 9;
106+
padding-bottom: 8px;
107+
border-bottom: 1px solid var(--color-border);
108+
margin-bottom: 10px;
69109
}
70110

71111
.LocalizationModal__translations__table__row + .LocalizationModal__translations__table__row {
@@ -74,17 +114,114 @@
74114
margin-top: 12px;
75115
}
76116

117+
.LocalizationModal__translations__table__row--header + .LocalizationModal__translations__table__row {
118+
border-top: none;
119+
padding-top: 0;
120+
margin-top: 0;
121+
}
122+
77123
.LocalizationModal__translations__table__header,
124+
.LocalizationModal__translations__table__col {
125+
text-align: left;
126+
overflow-wrap: break-word;
127+
word-break: break-word;
128+
min-width: 0;
129+
}
130+
78131
.LocalizationModal__translations__table__col {
79132
padding-left: 8px;
80133
padding-right: 8px;
81-
text-align: left;
134+
}
135+
136+
.LocalizationModal__translations__localeHeader {
137+
display: flex;
138+
align-items: center;
139+
justify-content: space-between;
140+
gap: 8px;
141+
}
142+
143+
.LocalizationModal__translations__missingToggle {
144+
display: flex;
145+
align-items: center;
146+
gap: 4px;
147+
white-space: nowrap;
148+
flex-shrink: 0;
149+
background: none;
150+
border: 1px solid transparent;
151+
border-radius: 4px;
152+
padding: 2px 8px;
153+
font-size: 12px;
154+
font-weight: 700;
155+
color: #000;
156+
cursor: pointer;
157+
}
158+
159+
.LocalizationModal__translations__missingToggle:hover {
160+
background-color: var(--mantine-color-gray-1, #f1f3f5);
161+
}
162+
163+
.LocalizationModal__translations__missingToggle--active {
164+
color: var(--mantine-color-blue-7, #1c7ed6);
165+
background-color: var(--mantine-color-blue-0, #e7f5ff);
166+
border-color: var(--mantine-color-blue-3, #74c0fc);
167+
}
168+
169+
.LocalizationModal__translations__fullyTranslated {
170+
display: flex;
171+
align-items: center;
172+
gap: 4px;
173+
white-space: nowrap;
174+
flex-shrink: 0;
175+
font-size: 12px;
176+
font-weight: 700;
177+
color: var(--mantine-color-green-7, #37b24d);
178+
}
179+
180+
.LocalizationModal__translations__fullyTranslated svg {
181+
background-color: var(--mantine-color-green-6, #40c057);
182+
color: white;
183+
border-radius: 50%;
184+
padding: 2px;
185+
}
186+
187+
.LocalizationModal__allNoneBtn:hover {
188+
background-color: var(--mantine-color-gray-0, #f8f9fa);
189+
}
190+
191+
.LocalizationModal__sourceCell {
192+
background-color: var(--mantine-color-gray-0, #f8f9fa);
193+
border: 1px solid var(--mantine-color-gray-3, #dee2e6);
194+
padding: 10px 20px;
195+
border-radius: 4px;
196+
height: 100%;
197+
position: relative;
198+
}
199+
200+
.LocalizationModal__sourceCell__text {
201+
font-size: 12px;
202+
white-space: pre-wrap;
203+
}
204+
205+
.LocalizationModal__sourceCell__link {
206+
position: absolute;
207+
top: 4px;
208+
right: 4px;
209+
opacity: 0;
210+
background: white;
211+
border: 1px solid var(--mantine-color-gray-4, #ced4da);
212+
border-radius: 4px;
213+
padding: 4px;
214+
}
215+
216+
.LocalizationModal__sourceCell:hover .LocalizationModal__sourceCell__link {
217+
opacity: 1;
82218
}
83219

84220
.LocalizationModal__translations__localeSelect {
85221
display: flex;
86222
gap: 8px;
87223
align-items: center;
224+
white-space: nowrap;
88225
}
89226

90227
.LocalizationModal__translations__menu__item .mantine-Menu-itemBody {
@@ -101,6 +238,8 @@
101238
display: flex;
102239
align-items: center;
103240
justify-content: space-between;
241+
flex-wrap: wrap;
242+
gap: 8px;
104243
}
105244

106245

@@ -114,3 +253,64 @@
114253
.LocalizationModal__missingTags__message svg {
115254
color: #FBC02D;
116255
}
256+
257+
.LocalizationModal__translations__cell--edited .mantine-Textarea-input {
258+
border-color: #228be6;
259+
background-color: #e7f5ff;
260+
}
261+
262+
.LocalizationModal__translations__cell--empty .mantine-Textarea-input {
263+
background-color: #FFF5F5;
264+
}
265+
266+
@keyframes shimmer-border {
267+
0% {
268+
border-color: #be4bdb;
269+
}
270+
25% {
271+
border-color: #9775fa;
272+
}
273+
50% {
274+
border-color: #da77f2;
275+
}
276+
75% {
277+
border-color: #9775fa;
278+
}
279+
100% {
280+
border-color: #be4bdb;
281+
}
282+
}
283+
284+
.LocalizationModal__translations__cell--ai-generating .mantine-Textarea-input {
285+
border-color: #be4bdb;
286+
background-color: #f8f0fc;
287+
animation: shimmer-border 1.5s ease-in-out infinite;
288+
}
289+
290+
@keyframes spin {
291+
from { transform: rotate(0deg); }
292+
to { transform: rotate(360deg); }
293+
}
294+
295+
.LocalizationModal__spinner {
296+
animation: spin 1s linear infinite;
297+
color: #868e96;
298+
}
299+
300+
.LocalizationModal__translations__saveBar {
301+
position: sticky;
302+
bottom: 0;
303+
background: var(--color-background, #fff);
304+
border-top: 1px solid var(--color-border);
305+
padding: 8px 0;
306+
display: flex;
307+
align-items: center;
308+
justify-content: flex-end;
309+
gap: 8px;
310+
z-index: 10;
311+
}
312+
313+
.LocalizationModal__translations__saveBar__status {
314+
font-size: 12px;
315+
color: #000;
316+
}

0 commit comments

Comments
 (0)