♻️ Improve export UI

This commit is contained in:
Eva Marco 2026-07-22 14:48:29 +02:00
parent 20c4d56ade
commit 1f412d3fdb
5 changed files with 259 additions and 297 deletions

View File

@ -17,7 +17,7 @@
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
(def valid-types (def valid-types
(d/ordered-set :all :merge :detach)) (d/ordered-set :all :merge :detach :link-later))
(def valid-formats (def valid-formats
#{:binfile-v1 :binfile-v3 :legacy-zip}) #{:binfile-v1 :binfile-v3 :legacy-zip})

View File

@ -13,8 +13,13 @@
[app.main.data.exports.files :as fexp] [app.main.data.exports.files :as fexp]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
[app.main.ui.ds.foundations.typography :as t]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.main.ui.ds.product.loader :refer [loader*]] [app.main.ui.ds.product.loader :refer [loader*]]
[app.main.ui.icons :as deprecated-icon]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -55,13 +60,20 @@
[:div {:class (stl/css :file-name)} [:div {:class (stl/css :file-name)}
(if (:loading file) (if (:loading file)
[:> loader* {:width 16 [:> loader* {:width 26
:title (tr "labels.loading")}] :title (tr "labels.loading")}]
[:span {:class (stl/css :file-icon)} (cond (:export-success? file)
(cond (:export-success? file) deprecated-icon/tick [:> icon* {:icon-id i/tick
(:export-error? file) deprecated-icon/close)]) :class (stl/css :file-icon)
:size "s"}]
(:export-error? file)
[:> icon* {:icon-id i/close
:class (stl/css :file-icon)
:size "s"}]))
[:div {:class (stl/css :file-name-label)} [:> text* {:class (stl/css :file-name-label)
:as "span"
:typography t/body-large}
(:name file)]]]) (:name file)]]])
(mf/defc export-dialog (mf/defc export-dialog
@ -119,38 +131,59 @@
[:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-container)} [:div {:class (stl/css :modal-container)}
[:div {:class (stl/css :modal-header)} [:div {:class (stl/css :modal-header)}
[:h2 {:class (stl/css :modal-title)} [:> heading* {:level 2
:typography t/headline-large
:class (stl/css :modal-title)}
(tr "files-download-modal.title")] (tr "files-download-modal.title")]
[:button {:class (stl/css :modal-close-btn) [:> icon-button* {:variant "ghost"
:on-click on-cancel} deprecated-icon/close]] :aria-label (tr "labels.close")
:on-click on-cancel
:class (stl/css :modal-close-btn)
:icon i/close}]]
(cond (cond
(= status :prepare) (= status :prepare)
[:* [:*
[:div {:class (stl/css :modal-content)} [:div {:class (stl/css :modal-content)}
[:p {:class (stl/css :modal-msg)} (tr "files-download-modal.description-1")] ;; TODO: Add translation
[:p {:class (stl/css :modal-scd-msg)} (tr "files-download-modal.description-2")] [:> text* {:as "p" :typography t/body-large :class (stl/css :modal-msg)}
"What do you want to do with linked libraries?"]
(for [type fexp/valid-types] (for [type fexp/valid-types]
[:div {:class (stl/css :export-option true) [:div {:class (stl/css :export-option true)
:key (name type)} :key (name type)}
[:label {:for (str "export-" type) [:label {:for (str "export-" type)
:class (stl/css-case :global/checked (= selected type))} :class (stl/css :export-option-label)}
;; Execution time translation strings: ;; Execution time translation strings:
;; (tr "files-download-modal.options.all.message") ;; (tr "files-export-modal.options.all.title")
;; (tr "files-download-modal.options.all.title") ;; (tr "files-export-modal.options.all.message")
;; (tr "files-download-modal.options.detach.message")
;; (tr "files-download-modal.options.detach.title") ;; (tr "files-export-modal.options.merge.title")
;; (tr "files-download-modal.options.merge.message") ;; (tr "files-export-modal.options.merge.message")
;; (tr "files-download-modal.options.merge.title")
[:span {:class (stl/css-case :global/checked (= selected type))} ;; (tr "files-export-modal.options.detach.title")
;; (tr "files-export-modal.options.detach.message")
;; (tr "files-export-modal.options.link-later.title")
;; (tr "files-export-modal.options.link-later.message")
[:span {:class (stl/css-case
:option-icon-wrapper true
:checked (= selected type))}
(when (= selected type) (when (= selected type)
deprecated-icon/status-tick)] [:svg {:class (stl/css :option-icon)
:viewBox "0 0 8 8"
:width 8
:height 8
:aria-hidden true}
[:circle {:cx 4 :cy 4 :r 4}]])]
[:div {:class (stl/css :option-content)} [:div {:class (stl/css :option-content)}
[:h3 {:class (stl/css :modal-subtitle)} [:> heading* {:level 3
(tr (dm/str "files-download-modal.options." (d/name type) ".title"))] :typography t/body-large
[:p {:class (stl/css :modal-msg)} :class (stl/css :option-title)}
(tr (dm/str "files-download-modal.options." (d/name type) ".message"))]] (tr (dm/str "files-export-modal.options." (d/name type) ".title"))]
[:> text* {:as "p" :typography t/body-large :class (stl/css :modal-msg)}
(tr (dm/str "files-export-modal.options." (d/name type) ".message"))]]
[:input {:type "radio" [:input {:type "radio"
:class (stl/css :option-input) :class (stl/css :option-input)
@ -162,15 +195,15 @@
[:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)} [:div {:class (stl/css :action-buttons)}
[:input {:class (stl/css :cancel-button) [:> button* {:variant "secondary"
:type "button" :type "button"
:value (tr "labels.cancel") :on-click on-cancel}
:on-click on-cancel}] (tr "labels.cancel")]
[:input {:class (stl/css :accept-btn) [:> button* {:variant "primary"
:type "button" :type "button"
:value (tr "labels.continue") :on-click on-accept}
:on-click on-accept}]]]] (tr "labels.continue")]]]]
(= status :exporting) (= status :exporting)
(let [in-progress? (->> state :files (some :loading))] (let [in-progress? (->> state :files (some :loading))]
@ -180,15 +213,15 @@
[:> export-entry* {:file file :key (dm/str (:id file))}]) [:> export-entry* {:file file :key (dm/str (:id file))}])
(when in-progress? (when in-progress?
[:div {:class (stl/css :status-message) [:> text* {:as "span" :typography t/body-large :class (stl/css :status-message)
:role "status" :role "status"
:aria-live "polite"} :aria-live "polite"}
(tr "labels.downloading-file")])] (tr "labels.downloading-file")])]
[:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)} [:div {:class (stl/css :action-buttons)}
[:input {:class (stl/css :accept-btn) [:> button* {:variant "primary"
:type "button" :type "button"
:value (tr "labels.close") :disabled in-progress?
:disabled in-progress? :on-click on-cancel}
:on-click on-cancel}]]]]))]])) (tr "labels.close")]]]]))]]))

View File

@ -4,289 +4,205 @@
// //
// Copyright (c) KALEIDOS INC Sucursal en España SL // Copyright (c) KALEIDOS INC Sucursal en España SL
@use "refactor/common-refactor.scss" as deprecated; @use "ds/typography.scss" as *;
@use "ds/_borders.scss" as *;
@use "ds/spacing.scss" as *;
@use "ds/_sizes.scss" as *;
@use "ds/_utils.scss" as *;
@use "ds/z-index.scss" as *;
// EXPORT MODAL // EXPORT MODAL
.modal-overlay { .modal-overlay {
@extend %modal-overlay-base; display: flex;
justify-content: center;
&.transparent { align-items: center;
background-color: transparent; position: fixed;
} inset-inline-start: 0;
inset-block-start: 0;
block-size: 100%;
inline-size: 100%;
z-index: var(--z-index-set);
background-color: var(--overlay-color);
} }
.modal-container { .modal-container {
@extend %modal-container-base; position: relative;
display: flex;
max-height: calc(10 * deprecated.$s-80); flex-direction: column;
} gap: var(--sp-xxxl);
padding: var(--sp-xxxl);
.modal-header { border-radius: $br-8;
margin-bottom: deprecated.$s-24; background-color: var(--color-background-primary);
} border: $b-2 solid var(--color-background-quaternary);
min-block-size: $sz-192;
.modal-title { inline-size: $sz-512;
@include deprecated.headline-medium-typography; max-block-size: calc(10 * px2rem(80));
color: var(--modal-title-foreground-color);
}
.modal-close-btn {
@extend %modal-close-btn-base;
} }
.modal-content { .modal-content {
@include deprecated.body-small-typography; display: flex;
flex-direction: column;
gap: var(--sp-l);
margin-block-end: var(--sp-xxl);
}
margin-bottom: deprecated.$s-24; .modal-content-extended {
gap: var(--sp-xxl);
}
.modal-link { .modal-title {
@include deprecated.body-large-typography; color: var(--color-foreground-primary);
}
text-decoration: none; .modal-close-btn {
cursor: pointer; position: absolute;
color: var(--modal-link-foreground-color); inset-block-start: var(--sp-m);
} inset-inline-end: var(--sp-m);
}
.selection-header { .modal-msg {
@include deprecated.flex-row; color: var(--color-foreground-secondary);
margin: 0;
}
height: deprecated.$s-32; .option-content {
margin-bottom: deprecated.$s-4; display: flex;
flex-direction: column;
.selection-btn {
@include deprecated.button-style;
@extend %input-checkbox;
@include deprecated.flex-center;
height: deprecated.$s-24;
width: deprecated.$s-24;
padding: 0;
margin-left: deprecated.$s-16;
span {
@extend %checkbox-icon;
}
}
.selection-title {
@include deprecated.body-large-typography;
color: var(--modal-text-foreground-color);
}
}
.selection-wrapper {
position: relative;
width: 100%;
height: fit-content;
}
.selection-shadow {
width: 100%;
height: 100%;
&::after {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 50px;
background: linear-gradient(to top, rgb(24 24 26 / 1) 0%, rgb(24 24 26 / 0) 100%);
content: "";
pointer-events: none;
}
}
.selection-list {
@include deprecated.flex-column;
max-height: deprecated.$s-400;
overflow-y: auto;
padding-bottom: deprecated.$s-12;
.selection-row {
@include deprecated.flex-row;
background-color: var(--entry-background-color);
min-height: deprecated.$s-40;
border-radius: deprecated.$br-8;
.selection-btn {
@include deprecated.button-style;
display: grid;
grid-template-columns: min-content auto 1fr auto auto;
align-items: center;
width: 100%;
height: 10%;
gap: deprecated.$s-8;
padding: 0 deprecated.$s-16;
.checkbox-wrapper {
@extend %input-checkbox;
@include deprecated.flex-center;
height: deprecated.$s-24;
width: deprecated.$s-24;
padding: 0;
.checkobox-tick {
@extend %checkbox-icon;
}
}
.selection-name {
@include deprecated.body-large-typography;
@include deprecated.text-ellipsis;
flex-grow: 1;
color: var(--modal-text-foreground-color);
text-align: start;
}
.selection-scale {
@include deprecated.body-large-typography;
@include deprecated.text-ellipsis;
min-width: deprecated.$s-108;
padding: deprecated.$s-12;
color: var(--modal-text-foreground-color);
}
.selection-extension {
@include deprecated.body-large-typography;
@include deprecated.text-ellipsis;
min-width: deprecated.$s-72;
padding: deprecated.$s-12;
color: var(--modal-text-foreground-color);
}
}
.image-wrapper {
@include deprecated.flex-center;
min-height: deprecated.$s-32;
min-width: deprecated.$s-32;
background-color: var(--app-white);
border-radius: deprecated.$br-6;
margin: auto 0;
img,
svg {
object-fit: contain;
max-height: deprecated.$s-40;
}
}
}
}
} }
.status-message { .status-message {
@include deprecated.body-small-typography; color: var(--color-foreground-primary);
color: var(--modal-title-foreground-color);
font-style: italic; font-style: italic;
} }
.action-buttons { .action-buttons {
@extend %modal-action-btns; display: flex;
} justify-content: flex-end;
gap: var(--sp-s);
.cancel-button {
@extend %modal-cancel-btn;
}
.accept-btn {
@extend %modal-accept-btn;
&.danger {
@extend %modal-danger-btn;
}
}
.modal-scd-msg,
.modal-subtitle,
.modal-msg {
@include deprecated.body-large-typography;
color: var(--modal-text-foreground-color);
} }
.export-option { .export-option {
@extend %input-checkbox; display: flex;
width: 100%;
align-items: flex-start; align-items: flex-start;
inline-size: 100%;
}
label { .export-option-label {
align-items: flex-start; --input-border-color: var(--input-checkbox-border-color-rest);
--input-icon-color: var(--color-background-primary);
.modal-subtitle { display: flex;
@include deprecated.body-large-typography; align-items: flex-start;
gap: px2rem(6);
cursor: pointer;
color: var(--color-foreground-primary);
color: var(--modal-title-foreground-color); &:hover {
padding: 0.25rem 0; --input-border-color: var(--color-accent-primary-muted);
}
} }
span { &:focus,
margin-top: deprecated.$s-8; &:focus-within {
--input-border-color: var(--color-accent-primary);
} }
} }
.option-content { .option-icon-wrapper {
@include deprecated.flex-column; --icon-display: none;
@include deprecated.body-large-typography; --background-color: var(--color-background-quaternary);
display: flex;
justify-content: center;
align-items: center;
inline-size: px2rem(16);
min-inline-size: px2rem(16);
block-size: px2rem(16);
margin-block-start: px2rem(10);
background-color: var(--background-color);
border: px2rem(1) solid var(--input-border-color);
border-radius: $br-circle;
&.checked {
--icon-display: block;
--input-border-color: var(--color-background-quaternary);
--input-icon-color: var(--color-background-primary);
--background-color: var(--color-accent-primary);
}
&:hover {
--input-border-color: var(--color-accent-primary-muted);
}
&:focus {
--input-border-color: var(--color-accent-primary);
}
}
.option-icon {
inline-size: px2rem(8);
block-size: px2rem(8);
display: var(--icon-display);
fill: var(--input-icon-color);
}
.option-input {
margin: 0;
} }
.file-entry { .file-entry {
.file-name { --file-entry-color: var(--color-foreground-secondary);
@include deprecated.flex-row;
.file-icon {
@include deprecated.flex-center;
height: deprecated.$s-16;
width: deprecated.$s-16;
svg {
@extend %button-icon-small;
stroke: var(--input-foreground);
}
}
.file-name-label {
@include deprecated.body-large-typography;
@include deprecated.text-ellipsis;
}
}
&.loading { &.loading {
.file-name { .file-name {
color: var(--modal-text-foreground-color); color: var(--color-foreground-secondary);
} }
} }
&.error { &.error {
.file-name { .file-name {
color: var(--modal-text-foreground-color); color: var(--color-foreground-secondary);
.file-icon svg { .file-icon svg {
stroke: var(--modal-text-foreground-color); stroke: var(--color-foreground-secondary);
} }
} }
} }
&.success { &.success {
.file-name { .file-name {
color: var(--modal-text-foreground-color); color: var(--color-foreground-secondary);
.file-icon svg { .file-icon svg {
stroke: var(--modal-text-foreground-color); stroke: var(--color-foreground-secondary);
} }
} }
} }
} }
.file-name {
display: flex;
align-items: center;
gap: var(--sp-m);
.file-icon {
display: flex;
justify-content: center;
align-items: center;
block-size: px2rem(16);
inline-size: px2rem(16);
color: var(--color-foreground-secondary);
}
.file-name-label {
display: block;
max-inline-size: 99%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.icon-status-tick {
fill: none;
stroke: var(--color-accent-primary);
}

View File

@ -2119,34 +2119,40 @@ msgid "files-download-modal.description-2"
msgstr "* Might include components, graphics, colors and/or typographies." msgstr "* Might include components, graphics, colors and/or typographies."
#: src/app/main/ui/exports/files.cljs:140 #: src/app/main/ui/exports/files.cljs:140
msgid "files-download-modal.options.all.message" msgid "files-export-modal.options.all.message"
msgstr "" msgstr ""
"Files with shared libraries will be included in the export, maintaining " "Files with linked libraries will be included in the export, maintaining "
"their linkage." "their linkage. "
#: src/app/main/ui/exports/files.cljs:141 #: src/app/main/ui/exports/files.cljs:141
msgid "files-download-modal.options.all.title" msgid "files-export-modal.options.all.title"
msgstr "Export shared libraries" msgstr "Export file + libraries"
#: src/app/main/ui/exports/files.cljs:142 #: src/app/main/ui/exports/files.cljs:142
msgid "files-download-modal.options.detach.message" msgid "files-export-modal.options.detach.message"
msgstr "" msgstr "Linked library assets won't be included in the file."
"Shared libraries will not be included in the export and no assets will be "
"added to the library. " #: src/app/main/ui/exports/files.cljs
msgid "files-export-modal.options.link-later.title"
msgstr "Link matching libraries on import"
#: src/app/main/ui/exports/files.cljs
msgid "files-export-modal.options.link-later.message"
msgstr "When imported, you'll be able to link existing libraries with matching names."
#: src/app/main/ui/exports/files.cljs:143 #: src/app/main/ui/exports/files.cljs:143
msgid "files-download-modal.options.detach.title" msgid "files-export-modal.options.detach.title"
msgstr "Treat shared library assets as basic objects" msgstr "Treat assets as basic objects"
#: src/app/main/ui/exports/files.cljs:144 #: src/app/main/ui/exports/files.cljs:144
msgid "files-download-modal.options.merge.message" msgid "files-export-modal.options.merge.message"
msgstr "" msgstr ""
"Your file will be exported with all external assets merged into the file " "Your file will be exported with library asset merged into the local "
"library." "library."
#: src/app/main/ui/exports/files.cljs:145 #: src/app/main/ui/exports/files.cljs:145
msgid "files-download-modal.options.merge.title" msgid "files-export-modal.options.merge.title"
msgstr "Include shared library assets in file libraries" msgstr "Embed library assets in the file"
#: src/app/main/ui/exports/files.cljs:123 #: src/app/main/ui/exports/files.cljs:123
msgid "files-download-modal.title" msgid "files-download-modal.title"

View File

@ -2067,33 +2067,40 @@ msgid "files-download-modal.description-2"
msgstr "* Pueden incluir components, gráficos, colores y/o tipografias." msgstr "* Pueden incluir components, gráficos, colores y/o tipografias."
#: src/app/main/ui/exports/files.cljs:140 #: src/app/main/ui/exports/files.cljs:140
msgid "files-download-modal.options.all.message" msgid "files-export-modal.options.all.message"
msgstr "" msgstr ""
"Ficheros con librerias compartidas se inclurán en el paquete de exportación " "Los ficheros con librerias compartidas se inclurán en el paquete de exportación "
"y mantendrán los enlaces." "y mantendrán los enlaces."
#: src/app/main/ui/exports/files.cljs:141 #: src/app/main/ui/exports/files.cljs:141
msgid "files-download-modal.options.all.title" msgid "files-export-modal.options.all.title"
msgstr "Exportar librerias compartidas" msgstr "Exportar archivo + librerías"
#: src/app/main/ui/exports/files.cljs:142 #: src/app/main/ui/exports/files.cljs:142
msgid "files-download-modal.options.detach.message" msgid "files-export-modal.options.detach.message"
msgstr "" msgstr ""
"Las biblioteca compartidas no se incluirán en la exportación y ningún " "Las recursos de las bibliotecas compartidas no se incluirán en la exportación."
"recurso será incluido en la biblioteca. "
#: src/app/main/ui/exports/files.cljs
msgid "files-export-modal.options.link-later.title"
msgstr "Vincular librerías al importar"
#: src/app/main/ui/exports/files.cljs
msgid "files-export-modal.options.link-later.message"
msgstr "Al importar, podrás vincular bibliotecas existentes con el mismo nombre."
#: src/app/main/ui/exports/files.cljs:143 #: src/app/main/ui/exports/files.cljs:143
msgid "files-download-modal.options.detach.title" msgid "files-export-modal.options.detach.title"
msgstr "Usar los recursos como objetos básicos" msgstr "Tratar los recursos como objetos básicos"
#: src/app/main/ui/exports/files.cljs:144 #: src/app/main/ui/exports/files.cljs:144
msgid "files-download-modal.options.merge.message" msgid "files-export-modal.options.merge.message"
msgstr "" msgstr ""
"Tu fichero será exportado con todos los recursos dentro de la libreria del " "Tu fichero será exportado con todos los recursos externos dentro de la libreria del "
"propio fichero." "propio fichero."
#: src/app/main/ui/exports/files.cljs:145 #: src/app/main/ui/exports/files.cljs:145
msgid "files-download-modal.options.merge.title" msgid "files-export-modal.options.merge.title"
msgstr "Incluir librerias compartidas dentro de las librerias del fichero" msgstr "Incluir librerias compartidas dentro de las librerias del fichero"
#: src/app/main/ui/exports/files.cljs:123 #: src/app/main/ui/exports/files.cljs:123