diff --git a/css/apps/files.scss b/css/apps/files.scss
index 44e852d..8ee3ae0 100644
--- a/css/apps/files.scss
+++ b/css/apps/files.scss
@@ -407,6 +407,30 @@ table.files-filestable {
}
}
+// Below 512px NC Teleports this to
as a bottom-corner FAB.
+// Selector must out-specify NC's `.--narrow[data-v-]` without using the hash.
+form.upload-picker.files-list__header-upload-button--narrow {
+ inset-block-start: 86px; // grid button y=90, less the 4px form inset
+ inset-block-end: auto;
+ inset-inline-end: 80px; // 24px header margin + 40px grid button + 16px gap
+
+ // NC sets `width: var(--button-size) !important` on icon-only buttons
+ button.action-item__menutoggle {
+ --button-size: 40px;
+
+ width: 40px !important;
+ height: 40px !important;
+ min-width: 40px !important;
+ min-height: 40px !important;
+
+ .button-vue__icon {
+ width: 40px;
+ min-width: 40px;
+ height: 40px;
+ }
+ }
+}
+
#app-content-vue {
// Override favorite marker stroke color
@@ -471,6 +495,55 @@ table.files-filestable {
}
+ .files-list__header-upload-button {
+ button.action-item__menutoggle {
+ all: unset;
+ align-items: center;
+ background-color: var(--color-primary);
+ border-radius: var(--border-radius-rounded);
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ height: 40px;
+ margin-inline-end: 1rem;
+
+ &:hover:not(:disabled) {
+ background-color: var(--color-primary-hover);
+ }
+
+ &:active:not(:disabled) {
+ background-color: var(--color-primary-pressed);
+ }
+
+ // all: unset strips the button-vue focus ring
+ &:focus-visible {
+ outline: 2px solid var(--color-main-text);
+ outline-offset: 2px;
+ }
+
+ .button-vue__icon {
+ background-image: var(--original-icon-add-white);
+ background-size: 18px;
+ opacity: 1;
+ width: 18px;
+ height: 18px;
+ background-position: center;
+ background-repeat: no-repeat;
+ margin-inline: 4px -4px;
+ min-width: 40px;
+
+ svg {
+ display: none;
+ }
+ }
+
+ .button-vue__text {
+ color: var(--nmc-color-text-and-icon-white);
+ padding-right: 1rem;
+ }
+ }
+ }
+
.upload-picker__progress {
width: 300px;
max-width: 320px;
diff --git a/src/nmcfiles.ts b/src/nmcfiles.ts
index b561abd..7be3ee2 100644
--- a/src/nmcfiles.ts
+++ b/src/nmcfiles.ts
@@ -98,15 +98,35 @@ if (sharingStatusAction) {
}
-function updateLabel(selector) {
- const buttonText = document.querySelector(selector)?.querySelector('.upload-picker')?.querySelector('.button-vue__text')
+/**
+ * NC33 labels the upload button "New"; production calls it "Add".
+ */
+function fixUploadButton(container: Element): void {
+ const buttonText = container.querySelector('.button-vue__text')
- if (buttonText) {
+ if (buttonText && buttonText.textContent !== t('nmctheme', 'Add')) {
buttonText.textContent = t('nmctheme', 'Add')
- return true
}
+}
- return false
+/**
+ * Watches the document because Vue re-renders the button on navigation.
+ */
+function setupUploadButtonFix(): void {
+ const apply = (): void => {
+ document.querySelectorAll('.files-list__header-upload-button').forEach(fixUploadButton)
+ }
+
+ apply()
+
+ const observer = new MutationObserver(() => apply())
+ observer.observe(document.body, { childList: true, subtree: true })
+}
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', setupUploadButtonFix)
+} else {
+ setupUploadButtonFix()
}
/**
@@ -325,33 +345,4 @@ if (document.readyState === 'loading') {
setupFilterRelocation()
}
-window.addEventListener('DOMContentLoaded', function() {
- const breadcrumb = document.querySelector('.breadcrumb')
- const empty = document.querySelector('.files-list__empty')
-
- if (breadcrumb) {
- const observer = new MutationObserver(() => {
- if (updateLabel('.breadcrumb')) {
- observer.disconnect()
- }
- })
-
- observer.observe(breadcrumb, {
- childList: true,
- subtree: true,
- })
- }
- if (empty) {
- const observerB = new MutationObserver(() => {
- if (updateLabel('.files-list__empty')) {
- observerB.disconnect()
- }
- })
-
- observerB.observe(empty, {
- childList: true,
- subtree: true,
- })
- }
-})