Add loader feedback while importing and exporting files (#9024)

*  Add loader feedback while importing and exporting files

Show a loader icon with a status label ("Importing files…" /
"Exporting files…") in the import and export dialog footers while the
operation is running, so users get clear in-progress feedback and
cannot retrigger the action by mistake.

Closes #9020

Signed-off-by: moorsecopers99 <patellscott18@gmail.com>

*  Address import/export loader feedback PR review

- Show the loader beside file names in the import dialog while files
  are being imported (previously queued entries kept showing the
  Penpot logo until each one moved into :import-progress).
- Drop the loader from the "Importing files…" / "Exporting files…"
  footer status, leaving just the text styled with the modal title
  color, per the design proposal.

Signed-off-by: moorsecopers99 <patellscott18@gmail.com>

*  Match design proposal for import/export progress feedback

- Move the in-progress label from the modal footer into the modal
  body, under the file rows, styled italic with the modal title
  color.
- Rename the labels to match the design wording: "Uploading file…"
  for import and "Downloading file…" for export.
- Restore the disabled "Accept" button in the import footer during
  the import-progress phase, mirroring the disabled "Close" button
  used by export.

Signed-off-by: moorsecopers99 <patellscott18@gmail.com>

* 🐛 Rename deprecated bodySmallTypography mixin to body-small-typography

Signed-off-by: moorsecopers99 <patellscott18@gmail.com>

---------

Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
moorsecopers99 2026-04-22 14:12:48 +03:00 committed by GitHub
parent 2579527e64
commit b6487015b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 52 additions and 14 deletions

View File

@ -12,6 +12,7 @@
- Show alpha percentage next to library color values to distinguish colors that differ only in opacity (by @rockchris099) [Github #6328](https://github.com/penpot/penpot/issues/6328) - Show alpha percentage next to library color values to distinguish colors that differ only in opacity (by @rockchris099) [Github #6328](https://github.com/penpot/penpot/issues/6328)
- Add "Clear artboard guides" option to right-click context menu for frames (by @eureka0928) [Github #6987](https://github.com/penpot/penpot/issues/6987) - Add "Clear artboard guides" option to right-click context menu for frames (by @eureka0928) [Github #6987](https://github.com/penpot/penpot/issues/6987)
- Add loader feedback while importing and exporting files [Github #9020](https://github.com/penpot/penpot/issues/9020)
- Allow duplicating color and typography styles (by @MkDev11) [Github #2912](https://github.com/penpot/penpot/issues/2912) - Allow duplicating color and typography styles (by @MkDev11) [Github #2912](https://github.com/penpot/penpot/issues/2912)
- Add woff2 support on user uploaded fonts (by @Nivl) [Github #8248](https://github.com/penpot/penpot/pull/8248) - Add woff2 support on user uploaded fonts (by @Nivl) [Github #8248](https://github.com/penpot/penpot/pull/8248)
- Import Tokens from linked library (by @dfelinto) [Github #8391](https://github.com/penpot/penpot/pull/8391) - Import Tokens from linked library (by @dfelinto) [Github #8391](https://github.com/penpot/penpot/pull/8391)

View File

@ -195,13 +195,14 @@
{::mf/props :obj {::mf/props :obj
::mf/memo true ::mf/memo true
::mf/private true} ::mf/private true}
[{:keys [entries entry edition can-be-deleted on-edit on-change on-delete]}] [{:keys [entries entry edition can-be-deleted importing? on-edit on-change on-delete]}]
(let [status (:status entry) (let [status (:status entry)
;; FIXME: rename to format ;; FIXME: rename to format
format (:type entry) format (:type entry)
loading? (or (= :analyze status) loading? (or (= :analyze status)
(= :import-progress status)) (= :import-progress status)
(and importing? (= :import-ready status)))
analyze-error? (= :analyze-error status) analyze-error? (= :analyze-error status)
import-success? (= :import-success status) import-success? (= :import-success status)
import-error? (= :import-error status) import-error? (= :import-error status)
@ -498,6 +499,7 @@
:key (dm/str (:uri entry) "/" (:file-id entry)) :key (dm/str (:uri entry) "/" (:file-id entry))
:entry entry :entry entry
:entries entries :entries entries
:importing? (= :import-progress status)
:on-edit on-edit :on-edit on-edit
:on-change on-entry-change :on-change on-entry-change
:on-delete on-entry-delete :on-delete on-entry-delete
@ -505,7 +507,13 @@
(when (some? template) (when (some? template)
[:> import-entry* {:entry (assoc template :status status) [:> import-entry* {:entry (assoc template :status status)
:can-be-deleted false}])] :can-be-deleted false}])
(when (= :import-progress status)
[:div {:class (stl/css :status-message)
:role "status"
:aria-live "polite"}
(tr "labels.uploading-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)}

View File

@ -43,6 +43,13 @@
min-height: 40px; min-height: 40px;
} }
.status-message {
@include deprecated.body-small-typography;
color: var(--modal-title-foreground-color);
font-style: italic;
}
.action-buttons { .action-buttons {
@extend %modal-action-btns; @extend %modal-action-btns;
} }

View File

@ -174,15 +174,22 @@
:on-click on-accept}]]]] :on-click on-accept}]]]]
(= status :exporting) (= status :exporting)
[:* (let [in-progress? (->> state :files (some :loading))]
[:div {:class (stl/css :modal-content)} [:*
(for [file (:files state)] [:div {:class (stl/css :modal-content)}
[:> export-entry* {:file file :key (dm/str (:id file))}])] (for [file (:files state)]
[:> export-entry* {:file file :key (dm/str (:id file))}])
[:div {:class (stl/css :modal-footer)} (when in-progress?
[:div {:class (stl/css :action-buttons)} [:div {:class (stl/css :status-message)
[:input {:class (stl/css :accept-btn) :role "status"
:type "button" :aria-live "polite"}
:value (tr "labels.close") (tr "labels.downloading-file")])]
:disabled (->> state :files (some :loading))
:on-click on-cancel}]]]])]])) [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)}
[:input {:class (stl/css :accept-btn)
:type "button"
:value (tr "labels.close")
:disabled in-progress?
:on-click on-cancel}]]]]))]]))

View File

@ -183,6 +183,13 @@
} }
} }
.status-message {
@include deprecated.body-small-typography;
color: var(--modal-title-foreground-color);
font-style: italic;
}
.action-buttons { .action-buttons {
@extend %modal-action-btns; @extend %modal-action-btns;
} }

View File

@ -2804,6 +2804,14 @@ msgstr "Libraries & Templates"
msgid "labels.loading" msgid "labels.loading"
msgstr "Loading…" msgstr "Loading…"
#: src/app/main/ui/dashboard/import.cljs
msgid "labels.uploading-file"
msgstr "Uploading file…"
#: src/app/main/ui/exports/files.cljs
msgid "labels.downloading-file"
msgstr "Downloading file…"
#: src/app/main/ui/workspace/sidebar/versions.cljs:210 #: src/app/main/ui/workspace/sidebar/versions.cljs:210
msgid "labels.lock" msgid "labels.lock"
msgstr "Lock" msgstr "Lock"