Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9667cb2
chore: polish localization modal
jeremydw Mar 13, 2026
44a0d8c
feat: enhance localization modal with inline editing and save functio…
jeremydw Mar 13, 2026
42899eb
feat: enhance localization modal with URL parameter handling and AI t…
jeremydw Mar 13, 2026
fd43314
fix: correct formatting of IconSparkles component in EditTranslations…
jeremydw Mar 13, 2026
496400e
add changeset
jeremydw Mar 13, 2026
dfe1b42
fix: enhance FileField to generate alt text for SVG images by fetchin…
jeremydw Mar 14, 2026
78cb7c6
fix: update flush method to support quiet option and enhance preview …
jeremydw Mar 14, 2026
55cf739
chore: undo changes to FileField
jeremydw Mar 17, 2026
e3494b3
fix: update StatusBar to use query parameters for locale and modal in…
jeremydw Mar 17, 2026
4e80df6
fix: enhance LocalizationModal layout and optimize locale translation…
jeremydw Mar 17, 2026
b497b17
chore: use useLocation for query param accessors
jeremydw Mar 19, 2026
60db10d
chore: restructure badge
jeremydw Mar 19, 2026
f06a843
fix: improve LocalizationModal styles and enhance button functionality
jeremydw Mar 19, 2026
d591590
feat: improve slug error messaging (#958)
jeremydw Mar 17, 2026
e905918
fix: support 'union' mode for batchUpdateTags (#957)
jeremydw Mar 17, 2026
0e93c28
chore: prevent empty data from saving on strings (#964)
jeremydw Mar 17, 2026
4697f29
feat: add usePageTitle hook and set page titles (#962)
jeremydw Mar 17, 2026
c2b34d0
feat: show referenced docs with unpublished changes in publish modal …
stevenle Mar 18, 2026
13d30a0
ci: release (#965)
github-actions[bot] Mar 18, 2026
7844118
ci: enable oidc tokens for npm trusted publishing (#967)
stevenle Mar 19, 2026
8d05c14
ci: unset NPM_TOKEN to force OIDC token
stevenle Mar 19, 2026
ffea28d
ci: move OIDC permissions to job config
stevenle Mar 19, 2026
820175c
ci: npm publish with provenance
stevenle Mar 19, 2026
f8646be
ci: fix npm publish with provenance
stevenle Mar 19, 2026
72f0c1e
ci: update npm to latest
stevenle Mar 19, 2026
c8aad8a
ci: fix build
stevenle Mar 19, 2026
8d63572
Merge branch 'main' into feat/localization-modal
jeremydw Mar 19, 2026
6f4e7b6
style: enhance LocalizationModal layout and header styling
jeremydw Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/empty-moles-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@blinkk/root-cms': patch
---

feat: add polish and features to localization modal
23 changes: 19 additions & 4 deletions packages/root-cms/ui/components/DocEditor/DocEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ type StatusBarProps = DocEditorProps & {
};

DocEditor.StatusBar = (props: StatusBarProps) => {
const {route} = useLocation();
const {route, query} = useLocation();
const {roles} = useProjectRoles();
const currentUserEmail = window.firebase.user.email || '';
const canPublish = testCanPublish(roles, currentUserEmail);
Expand Down Expand Up @@ -212,6 +212,20 @@ DocEditor.StatusBar = (props: StatusBarProps) => {
const publishDocModal = usePublishDocModal({docId: props.docId});
const localizationModal = useLocalizationModal();

const urlLocale = (query.locale as string) || '';
const urlModal = (query.modal as string) || '';

useEffect(() => {
if (urlModal === 'localization' && draft.controller) {
localizationModal.open({
docId: props.docId,
collection: props.collection,
draft: draft.controller,
locale: urlLocale || undefined,
});
}
}, []);

const loading = !data?.sys;
if (loading) {
return null;
Expand All @@ -234,13 +248,14 @@ DocEditor.StatusBar = (props: StatusBarProps) => {
color="dark"
size="xs"
leftIcon={<IconPlanet size={16} />}
onClick={() =>
onClick={() => {
localizationModal.open({
docId: props.docId,
collection: props.collection,
draft: draft.controller,
})
}
locale: (query.locale as string) || undefined,
});
}}
>
Localization
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,24 @@ export function EditTranslationsModal(
position="left"
>
<ActionIcon
variant="light"
variant="outline"
onClick={generateAiTranslations}
loading={aiGenerating}
disabled={aiGenerating}
size="sm"
sx={{
height: 30,
width: 30,
borderColor: '#ced4da',
}}
>
{aiGenerating ? (
<IconLoader2 size={16} />
) : (
<IconSparkles size={16} />
<IconSparkles
size={16}
fill="currentColor"
stroke={1.5}
/>
)}
</ActionIcon>
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,110 @@
padding: 30px 40px;
}

.mantine-Modal-modal:has(.LocalizationModal__layout) {
padding-bottom: 0;
}

.mantine-Modal-modal:has(.LocalizationModal__layout) .mantine-Modal-header {
transform: translateY(-10px);
}

.LocalizationModal__layout {
display: grid;
grid-template-columns: 400px 1fr;
grid-template-columns: minmax(auto, 400px) 1fr;
margin-top: -20px;
margin-bottom: 20px;
}

@media (max-width: 1024px) {
.LocalizationModal__layout {
grid-template-columns: minmax(auto, 200px) 1fr;
}
}

.LocalizationModal__iconTitle {
display: flex;
align-items: center;
gap: 8px;
white-space: nowrap;
}

.LocalizationModal__locales,
.LocalizationModal__translations {
height: 100%;
min-height: 400px;
padding-top: 30px;
padding-bottom: 30px;
}

.LocalizationModal__locales {
padding-right: 30px;
padding-top: 30px;
}

.LocalizationModal__translations {
border-left: 1px solid var(--color-border);
padding-left: 30px;
margin-right: -30px;
padding-right: 30px;
max-height: 80vh;
overflow: auto;
margin-left: -30px;
margin-right: -21px;
padding-bottom: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
}

.LocalizationModal__translations__header {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
align-items: flex-start;
gap: 12px;
position: sticky;
top: 0;
background: var(--color-background, #fff);
z-index: 10;
padding-top: 8px;
padding-bottom: 10px;
}

.LocalizationModal__translations__header__buttons {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
justify-content: flex-end;
}

.LocalizationModal__translations__titleWrap {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
min-width: 0;
}

.LocalizationModal__translations__table {
display: flex;
flex-direction: column;
width: 100%;
margin-bottom: 12px;
}

.LocalizationModal__translations__table__row {
display: grid;
grid-template-columns: 1fr 1fr;
min-width: 0;
}

.LocalizationModal__translations__table__row--header {
align-items: center;
position: sticky;
top: 48px;
background: var(--color-background, #fff);
z-index: 9;
padding-bottom: 8px;
border-bottom: 1px solid var(--color-border);
margin-bottom: 10px;
}

.LocalizationModal__translations__table__row + .LocalizationModal__translations__table__row {
Expand All @@ -74,17 +114,114 @@
margin-top: 12px;
}

.LocalizationModal__translations__table__row--header + .LocalizationModal__translations__table__row {
border-top: none;
padding-top: 0;
margin-top: 0;
}

.LocalizationModal__translations__table__header,
.LocalizationModal__translations__table__col {
text-align: left;
overflow-wrap: break-word;
word-break: break-word;
min-width: 0;
}

.LocalizationModal__translations__table__col {
padding-left: 8px;
padding-right: 8px;
text-align: left;
}

.LocalizationModal__translations__localeHeader {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}

.LocalizationModal__translations__missingToggle {
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
flex-shrink: 0;
background: none;
border: 1px solid transparent;
border-radius: 4px;
padding: 2px 8px;
font-size: 12px;
font-weight: 700;
color: #000;
cursor: pointer;
}

.LocalizationModal__translations__missingToggle:hover {
background-color: var(--mantine-color-gray-1, #f1f3f5);
}

.LocalizationModal__translations__missingToggle--active {
color: var(--mantine-color-blue-7, #1c7ed6);
background-color: var(--mantine-color-blue-0, #e7f5ff);
border-color: var(--mantine-color-blue-3, #74c0fc);
}

.LocalizationModal__translations__fullyTranslated {
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
flex-shrink: 0;
font-size: 12px;
font-weight: 700;
color: var(--mantine-color-green-7, #37b24d);
}

.LocalizationModal__translations__fullyTranslated svg {
background-color: var(--mantine-color-green-6, #40c057);
color: white;
border-radius: 50%;
padding: 2px;
}

.LocalizationModal__allNoneBtn:hover {
background-color: var(--mantine-color-gray-0, #f8f9fa);
}

.LocalizationModal__sourceCell {
background-color: var(--mantine-color-gray-0, #f8f9fa);
border: 1px solid var(--mantine-color-gray-3, #dee2e6);
padding: 10px 20px;
border-radius: 4px;
height: 100%;
position: relative;
}

.LocalizationModal__sourceCell__text {
font-size: 12px;
white-space: pre-wrap;
}

.LocalizationModal__sourceCell__link {
position: absolute;
top: 4px;
right: 4px;
opacity: 0;
background: white;
border: 1px solid var(--mantine-color-gray-4, #ced4da);
border-radius: 4px;
padding: 4px;
}

.LocalizationModal__sourceCell:hover .LocalizationModal__sourceCell__link {
opacity: 1;
}

.LocalizationModal__translations__localeSelect {
display: flex;
gap: 8px;
align-items: center;
white-space: nowrap;
}

.LocalizationModal__translations__menu__item .mantine-Menu-itemBody {
Expand All @@ -101,6 +238,8 @@
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 8px;
}


Expand All @@ -114,3 +253,64 @@
.LocalizationModal__missingTags__message svg {
color: #FBC02D;
}

.LocalizationModal__translations__cell--edited .mantine-Textarea-input {
border-color: #228be6;
background-color: #e7f5ff;
}

.LocalizationModal__translations__cell--empty .mantine-Textarea-input {
background-color: #FFF5F5;
}

@keyframes shimmer-border {
0% {
border-color: #be4bdb;
}
25% {
border-color: #9775fa;
}
50% {
border-color: #da77f2;
}
75% {
border-color: #9775fa;
}
100% {
border-color: #be4bdb;
}
}

.LocalizationModal__translations__cell--ai-generating .mantine-Textarea-input {
border-color: #be4bdb;
background-color: #f8f0fc;
animation: shimmer-border 1.5s ease-in-out infinite;
}

@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

.LocalizationModal__spinner {
animation: spin 1s linear infinite;
color: #868e96;
}

.LocalizationModal__translations__saveBar {
position: sticky;
bottom: 0;
background: var(--color-background, #fff);
border-top: 1px solid var(--color-border);
padding: 8px 0;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
z-index: 10;
}

.LocalizationModal__translations__saveBar__status {
font-size: 12px;
color: #000;
}
Loading
Loading