diff --git a/package-lock.json b/package-lock.json index d06bc19..0f980a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2467,9 +2467,9 @@ } }, "node_modules/@iconify-json/lucide": { - "version": "1.2.147", - "resolved": "https://registry.npmjs.org/@iconify-json/lucide/-/lucide-1.2.147.tgz", - "integrity": "sha512-7Qqa/joSBeUxihWsQJx5nKcqMWtV3YrH90Jldxcx4J9ciTLavRUlpexQwRTcx9dcb7CJpISfjZTj42zD/30sqA==", + "version": "1.2.149", + "resolved": "https://registry.npmjs.org/@iconify-json/lucide/-/lucide-1.2.149.tgz", + "integrity": "sha512-5NG9YdbtRS03hG1A+EIE6nLhhdAYsf0mKu1ZRi6kLMlCG8DxmDsRM6DAhwlNMLiSiQKFbHpKTJ2VddZdwUkUyw==", "dev": true, "license": "ISC", "dependencies": { @@ -3217,9 +3217,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz", + "integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==", "license": "MIT" }, "node_modules/@types/json-schema": { @@ -3860,9 +3860,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.33.tgz", - "integrity": "sha512-yiVKDX+qCMRKBE084lXvq9EcwFUhKZ2nU8TK1EQQuOgPNR/lmbGxXOeDdlGUqC2Zz11Cs9rk1d/8NfgBmlkt0w==", + "version": "2.11.34", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.34.tgz", + "integrity": "sha512-Aqr8mA1kIvyJ3UY5YAY7ib8LSo1DmDMbMnVqGPtsKW1LxaFQFwn9Eb3yvq2fUKJsRvaXjnAV7R5osqETapzNiA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3966,9 +3966,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001819", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001819.tgz", - "integrity": "sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==", + "version": "1.0.30001820", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001820.tgz", + "integrity": "sha512-gfWD6MxqVCqAOwmODfZf7DchWvlrA+SRdNX7ceLfg3xRqe5ssjjpF7EgslC/0tiLiNTajdaNN/q8c/5u/7Gz8w==", "dev": true, "funding": [ { @@ -4156,9 +4156,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.465", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.465.tgz", - "integrity": "sha512-zg4iUpbeGw7YNZsswc2xKr2uiBex2d8dELAXo92Icw3but1ULbrvK8USe6wVLaWjgJnKBARv0pchx9Owktx6wQ==", + "version": "1.5.467", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.467.tgz", + "integrity": "sha512-Nw9X371rtZmYcBSnEijnCDONILjs93biCZO34juC7MBOmK8E+GFnyD4T/WvyrlJkppul7oxg6TwvtKst9SODTw==", "dev": true, "license": "ISC" }, @@ -4494,9 +4494,9 @@ } }, "node_modules/exsolve": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.3.tgz", - "integrity": "sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.2.0.tgz", + "integrity": "sha512-h1pQPR9XoeSMdntRNCjyTznaume4UpfXrULBnlkZ2CUM/G5eSa+pBByGldO5uR8dxbPC+OuJXsPPNf+JZ81ADg==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 185071e..282a833 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "lint-fix": "eslint --fix", "typecheck": "tsc --noEmit", "test": "vitest run", - "prepublishOnly": "npm run build && npm run lint", + "prepublishOnly": "npm run build && npm run lint && npm run test", "preversion": "npm run typecheck && npm run lint", "postpublish": "git push origin staging", "start": "vite" diff --git a/src/components/folder-pane-container/FolderPaneContainer.styles.css b/src/components/folder-pane-container/FolderPaneContainer.styles.css index 56789dc..d862c40 100644 --- a/src/components/folder-pane-container/FolderPaneContainer.styles.css +++ b/src/components/folder-pane-container/FolderPaneContainer.styles.css @@ -12,8 +12,10 @@ display: flex; flex: 1 1 auto; flex-direction: column; + height: 100%; min-height: 0; width: 100%; + box-sizing: border-box; overflow-y: auto; overflow-x: hidden; scrollbar-width: thin; @@ -65,10 +67,10 @@ .resource-grid { display: flex; + align-items: center; flex-wrap: wrap; flex: 1 1 auto; align-content: flex-start; - align-items: flex-start; gap: 20px; width: 100%; min-height: 0; @@ -83,9 +85,10 @@ position: relative; display: flex; flex-direction: column; - flex: 0 0 auto; - width: 206px; - max-width: 100%; + flex: 1 1 206px; + width: min(206px, 100%); + min-width: 0; + max-width: 206px; height: 145.824px; border-radius: 5px; border: 1px solid var(--solid-ui-color-gray-200, #cbd5e1); @@ -124,6 +127,8 @@ .resource-grid-icon icon-lucide-file { width: 64px; height: 64px; + color: var(--solid-ui-color-gray-500, #6a7282); + stroke: var(--solid-ui-color-gray-500, #6a7282); } .resource-grid-icon--container { @@ -197,6 +202,23 @@ outline-offset: -2px; } + @media (max-width: 768px) { + .resource-grid { + gap: 15px; + } + + .resource-grid, + .resource-list { + padding: 0; + } + + .resource-grid-item { + flex: 0 0 calc((100% - 15px) / 2); + width: calc((100% - 15px) / 2); + max-width: none; + } + } + .resource-list-main { display: flex; align-items: center; diff --git a/src/components/folder-pane-container/FolderPaneContainer.ts b/src/components/folder-pane-container/FolderPaneContainer.ts index 4d9200e..9419bad 100644 --- a/src/components/folder-pane-container/FolderPaneContainer.ts +++ b/src/components/folder-pane-container/FolderPaneContainer.ts @@ -110,7 +110,7 @@ export default class FolderPaneContainer extends WebComponent { private isRootSpecialFolder (resource: Resource) { if (!resource.isContainer) return false const label = utils.label(resource.subject).toLowerCase() - return label === 'public' || label === 'trash' + return label === 'public' } private getResourcesFromStore () { diff --git a/src/components/folder-pane-content/FolderPaneContent.styles.css b/src/components/folder-pane-content/FolderPaneContent.styles.css index 33d3d16..9bb97f6 100644 --- a/src/components/folder-pane-content/FolderPaneContent.styles.css +++ b/src/components/folder-pane-content/FolderPaneContent.styles.css @@ -1,7 +1,14 @@ :host { display: flex; + box-sizing: border-box; flex-direction: column; flex: 1 1 0%; + padding: 10px 16px; + align-items: stretch; + gap: 20px; + flex-shrink: 0; + align-self: stretch; + height: 100%; width: 100%; min-width: 0; min-height: 0; diff --git a/src/components/folder-pane-sidebar/FolderPaneSidebar.styles.css b/src/components/folder-pane-sidebar/FolderPaneSidebar.styles.css index d1fcd42..3f4b305 100644 --- a/src/components/folder-pane-sidebar/FolderPaneSidebar.styles.css +++ b/src/components/folder-pane-sidebar/FolderPaneSidebar.styles.css @@ -122,8 +122,7 @@ } .resource-row-special icon-lucide-folder, - .resource-row-special icon-lucide-globe, - .resource-row-special icon-lucide-trash-2 { + .resource-row-special icon-lucide-globe { width: 16px; height: 16px; flex-shrink: 0; diff --git a/src/components/folder-pane-sidebar/FolderPaneSidebar.ts b/src/components/folder-pane-sidebar/FolderPaneSidebar.ts index d39f8e2..f15ef76 100644 --- a/src/components/folder-pane-sidebar/FolderPaneSidebar.ts +++ b/src/components/folder-pane-sidebar/FolderPaneSidebar.ts @@ -10,11 +10,10 @@ import '~icons/lucide/chevron-right' import '~icons/lucide/circle-small' import '~icons/lucide/folder' import '~icons/lucide/globe' -import '~icons/lucide/trash-2' import { getResourcesForContainer, type FolderPaneResourceLogic } from '../../helpers' import * as debug from '../../debug' -type SpecialIcon = 'folder' | 'globe' | 'trash' +type SpecialIcon = 'folder' | 'globe' @customElement('folder-pane-sidebar') export default class FolderPaneSidebar extends WebComponent { @@ -203,7 +202,6 @@ export default class FolderPaneSidebar extends WebComponent { private renderSpecialIcon (icon: SpecialIcon) { if (icon === 'globe') return html`` - if (icon === 'trash') return html`` return html`` } @@ -247,7 +245,6 @@ export default class FolderPaneSidebar extends WebComponent { return index >= 0 ? orderedResources.splice(index, 1)[0] : null } const publicResource = takeNamed('public') - const trashResource = takeNamed('trash') return html` ` } diff --git a/src/components/folder-pane-storage-header/FolderPaneStorageHeader.styles.css b/src/components/folder-pane-storage-header/FolderPaneStorageHeader.styles.css index ee66177..8e45bb8 100644 --- a/src/components/folder-pane-storage-header/FolderPaneStorageHeader.styles.css +++ b/src/components/folder-pane-storage-header/FolderPaneStorageHeader.styles.css @@ -15,6 +15,43 @@ padding: 10px 0; } +.folder-pane-storage-header-locations { + display: none; + align-items: center; + gap: 4px; + flex: 0 0 auto; +} + +.folder-pane-storage-header-locations button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 5.6px; + padding: 5.6px 8px; + border: 0; + background: transparent; + color: var(--solid-ui-color-gray-600, #4a5565); + cursor: pointer; + font: inherit; + font-size: var(--solid-ui-font-size-sm, 0.875rem); + font-weight: 500; + text-align: center; + border-bottom: 2px solid transparent; +} + +.folder-pane-storage-header-locations button[aria-current='page'] { + border-bottom-color: var(--solid-ui-color-primary, #7c4dff); + color: var(--solid-ui-color-primary, #7c4dff); + font-weight: 600; +} + +.folder-pane-storage-location icon-lucide-folder, +.folder-pane-storage-location icon-lucide-globe { + width: 1rem; + height: 1rem; + flex: 0 0 auto; +} + .folder-pane-storage-header-breadcrumbs, .folder-pane-storage-header-breadcrumbs ol, .folder-pane-storage-header-breadcrumbs li, @@ -26,7 +63,7 @@ .folder-pane-storage-header-breadcrumbs { min-width: 0; - gap: 0.35rem; + gap: 5.6px; overflow-x: auto; overflow-y: hidden; } @@ -41,7 +78,7 @@ .folder-pane-storage-header-breadcrumbs ol { min-width: 0; flex-wrap: nowrap; - gap: 0.35rem; + gap: 5.6px; margin: 0; padding: 0; list-style: none; @@ -51,7 +88,7 @@ .folder-pane-storage-header-breadcrumbs li { min-width: 0; - gap: 0.35rem; + gap: 5.6px; } .folder-pane-storage-header-breadcrumbs button { @@ -75,17 +112,18 @@ .folder-pane-storage-header-toolbar { flex: 0 0 auto; justify-content: flex-end; - gap: 0.5rem; + gap: 8px; min-width: 0; + padding-right: var(--folder-pane-storage-toolbar-right-padding, 0); } .folder-pane-storage-header-search { display: none; align-items: center; - gap: 0.35rem; + gap: 5.6px; min-width: 8rem; max-width: 14rem; - padding: 0.25rem 0.5rem; + padding: 4px 8px; border: 1px solid var(--solid-ui-color-gray-300, #d1d5dc); border-radius: 0.35rem; color: var(--solid-ui-color-gray-500, #6a7282); @@ -158,6 +196,42 @@ margin-left: 22px; } +.folder-pane-storage-header-add-trigger { + display: inline-flex; + align-items: center; +} + +.folder-pane-storage-header-add-button { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 5.6px; + min-height: 36px; + padding: 5.6px 12px; + border: 0; + border-radius: 5.6px; + background: var(--solid-ui-color-primary, #7c4dff); + color: var(--solid-ui-color-white, #ffffff); + cursor: pointer; + font: inherit; +} + +.folder-pane-storage-header-add-button:hover { + background: var(--solid-ui-color-primary-hover, #b9a2ff); +} + +.folder-pane-storage-header-add-button:focus-visible { + outline: 2px solid var(--solid-ui-color-primary, #7c4dff); + outline-offset: 2px; +} + +.folder-pane-storage-header-add-button icon-lucide-plus, +.folder-pane-storage-header-add-chevron { + width: 1.25rem; + height: 1.25rem; + flex: 0 0 auto; +} + .folder-pane-storage-header-add-menu img[slot="left-icon"] { display: block; width: 1.25rem; @@ -170,3 +244,77 @@ width: 13.333px; height: 12.664px; } + +@media (max-width: 768px) { + .folder-pane-storage-header { + flex-wrap: wrap; + gap: var(--folder-pane-storage-header-mobile-gap, 8px); + padding: var(--folder-pane-storage-header-mobile-padding, 10px 0); + border-bottom: 1px solid var(--solid-ui-color-gray-200, #e5e7eb); + } + + .folder-pane-storage-header-breadcrumbs { + display: none; + } + + .folder-pane-storage-header-locations { + display: flex; + width: 100%; + } + + .folder-pane-storage-header-breadcrumbs { + flex: 1 1 auto; + max-width: 100%; + } + + .folder-pane-storage-header-toolbar { + flex: 0 1 auto; + margin-left: auto; + } + + .folder-pane-storage-header-add-menu { + margin: 0; + } + + .folder-pane-storage-header-add-trigger { + position: fixed; + right: 30px; + bottom: 50px; + z-index: 200; + display: flex; + width: 50px; + height: 50px; + box-sizing: border-box; + padding: 9.722px 13.889px; + justify-content: center; + align-items: center; + gap: 11.111px; + aspect-ratio: 1 / 1; + border-radius: 6.944px; + background: var(--solid-ui-color-primary, #7c4dff); + box-shadow: 1.389px 5.556px 9.722px 0 rgb(0 0 0 / 56%); + } + + .folder-pane-storage-header-add-button { + width: 100%; + height: 100%; + box-sizing: border-box; + min-height: 0; + padding: 0; + background: transparent; + } + + .folder-pane-storage-header-add-button:hover { + background: transparent; + } + + .folder-pane-storage-header-add-button icon-lucide-plus { + width: 20px; + height: 20px; + } + + .folder-pane-storage-header-add-label, + .folder-pane-storage-header-add-chevron { + display: none; + } +} diff --git a/src/components/folder-pane-storage-header/FolderPaneStorageHeader.ts b/src/components/folder-pane-storage-header/FolderPaneStorageHeader.ts index 59e8639..c208ffc 100644 --- a/src/components/folder-pane-storage-header/FolderPaneStorageHeader.ts +++ b/src/components/folder-pane-storage-header/FolderPaneStorageHeader.ts @@ -8,6 +8,8 @@ import 'solid-ui/components/button' import 'solid-ui/components/menu' import 'solid-ui/components/menu-item' import '~icons/lucide/folder-open' +import '~icons/lucide/folder' +import '~icons/lucide/globe' import '~icons/lucide/layout-grid' import '~icons/lucide/list' import '~icons/lucide/chevron-down' @@ -28,6 +30,9 @@ export default class FolderPaneStorageHeader extends WebComponent { @property({ attribute: false }) accessor selectedResource: NamedNode | undefined = undefined + @property({ attribute: false }) + accessor publicResource: NamedNode | undefined = undefined + @property({ attribute: false }) accessor browserContext: DataBrowserContext | undefined = undefined @@ -118,6 +123,23 @@ export default class FolderPaneStorageHeader extends WebComponent { })) } + private isWithin (resource: NamedNode | undefined, ancestor: NamedNode | undefined) { + if (!resource || !ancestor) return false + let current: NamedNode | undefined = resource + for (let depth = 0; current && depth < 64; depth++) { + if (current.sameTerm(ancestor)) return true + const parent = current.dir() + if (!parent || parent.sameTerm(current)) break + current = parent + } + return false + } + + private isHomeSelected () { + return this.isWithin(this.selectedResource, this.subject) && + !this.isWithin(this.selectedResource, this.publicResource) + } + private updateSearch (event: Event) { this.dispatchEvent(new CustomEvent('folder-pane-search', { detail: { query: (event.target as HTMLInputElement).value }, @@ -137,6 +159,22 @@ export default class FolderPaneStorageHeader extends WebComponent { render () { return html`
+