Skip to content

New layout playground - #869

Draft
SharonStrats wants to merge 15 commits into
stagingfrom
new-layout-playground
Draft

SharonStrats wants to merge 15 commits into
stagingfrom
new-layout-playground

Conversation

@SharonStrats

Copy link
Copy Markdown
Contributor

No description provided.

@SharonStrats

SharonStrats commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

@NoelDeMartin so here I added to the solid-ui-provider. I also extended the menu to allow me to change the font size and gap because the 3 dot menu has different styling. And oops I'm tired 😅 I just realized this is where I have moved the file explorer web components so I can use them in both solid-panes and folder-pane.

Highlevel for providers we have
solid-ui-provider. (auth, and I thought we should add store here which I've done)
file-explorer-provider
storage-pane-provider. (and source-pane-provider) sitting at this same level

@NoelDeMartin NoelDeMartin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a bunch of comments about specific things to improve, but in general I think it's looking good and using the Design System components correctly :).

The only thing I wonder is whether the file explorer should really be a component from solid-ui, or a dedicated pane. Either way, I think everything should be as encapsulated as possible. In general, I think it's better to expose as little public API as possible and just expose helpers or reusable functionality as necessary. Otherwise, you risk breaking dependencies if you later want to refactor something that should have been internal.

}
}

render () {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"provider" components should always be headless, meaning that they only render a <slot> for their children. For example, that's how <solid-ui-provider> works (It does also render the dialogs root, but that's fine since those are absolutely positioned).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhhh I did not know that.

import FileExplorerHeader from './FileExplorerHeader'
import FileExplorerProvider from './FileExplorerProvider'

export { FileExplorerHeader, FileExplorerProvider }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This folder is exporting 2 components, but if those 2 are supposed to be "public", they should each have their own folder.

However, looking at how all the file-explorer is structured, I wonder if this needs to be within solid-ui at all? Shouldn't it be a pane instead?

Either way, if this really ends up as a component in solid-ui, I think it should just be <solid-ui-file-explorer>, and all the other components and helpers should be internal to the package.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok, I'll do that. It has to be in solid-ui because both solid-panes and folder-pane use them.

return html`
<solid-ui-menu>
<solid-ui-button slot="trigger" variant="ghost" title="More options">
<icon-lucide-ellipsis-vertical slot="icon" class="ellipsisIcon"></icon-lucide-ellipsis-vertical>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have seen this mistake in a lot of places during my review, so I won't address all of them. But in general, it's not a good a11y practice to have buttons without text content. I realize this button has a "title", but many accessibility tools ignore that attribute completely. Furthermore, even using aria-label is not ideal because translation tools often ignore it. The best approach is to simply add a <span class="sr-only"> inside of the button. It's ok if the text is the same as the title, those serve different purposes (one is for visually impaired users, the other one is for mouse users hovering the button).


let icon: HTMLElement | undefined
if (pane.name === 'profile') {
icon = dom.createElement('icon-lucide-user')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid using this imperative API. Instead, the icons can be rendered like this:

html`<icon-lucide-user slot="left-icon"></icon-lucide-user>`

Other than that, I don't see ~icons/lucide/user being imported in this file. Components should always be imported where they are declared (same for the users icon down below, etc.).

? html`
<file-explorer-header
.paneIcon=${this.getPaneIcon(this.pane, subject, this.context)}
.menuItems=${this.menuItems}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should have a different name, maybe extraMenuItems? It seems like the file explorer already has some built-in menu items that cannot be controlled by this property. So this actually only serves to add some additional entries.

color: var(--solid-ui-color-gray-600);
font-weight: 500;
font-size: var(--solid-ui-font-size-md);
font-size: var(--solid-ui-menu-item-font-size, var(--solid-ui-font-size-md));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed we're adding some modifications here, and overriding a lot of the styles for the menu in other parts of the code. This should be avoided if possible, the point of the Design System is that we reuse component and styles. If we want something to be customizable, it should be with component properties. For example, if we want menus with bigger or smaller font sizes, we could have a size property on the top <solid-ui-menu> component.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh Ok I put it in the wrong place.. makes sense.

}
}

solid-ui-menu::part(menu) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in the other comment, we should override Design System styles so aggressively. It's ok to override some things in some edge cases or something, but if you're redefining the styles of the component completely, you probably need to fix the underlying component instead (or maybe create a new component altogether).

menuItems?: ResourceActionMenuItem[]
}

export function getVisibleResourceActions (options: ResourceActionsMenuOptions): ResourceActionMenuItem[] {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this exported to the public and in a separate file? Couldn't it be just a private method in the component?

private: boolean
}

export async function loadDiscoveryState (subject: NamedNode): Promise<DiscoveryState> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why this and the resource-actions-menu.ts helpers are exported from the library, and even declared outside of the component folders. Shouldn't these be internal helpers for the file explorer components?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look at what you are saying. I had to have this in 2 places folder-pane and solid-panes if I remember right htat is why, but I'll see if I can do that better.

panes: Array<PaneDefinition> = context.session.paneRegistry.list
): Promise<Array<PaneDefinition>> {
const relevantPaneCandidates = panes.filter(
(pane) => pane.label(subject, context) && !pane.global && pane.name !== 'sharing'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the best way to get the relevant pane, what if a pane has a fallback label for unknown subjects such as "Unknown"? I'm not super familiar with how components are resolved, or how do we decide which pane should be used to render a certain subject. But I think it should be more robust that just looking for an empty label.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will have a look. I took this code how it was.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Critical and moderate correctness, accessibility, registration, and build issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 3 High severity · 4 Medium severity

Open (7)
What changed in this PR

Adds a file-explorer layout playground with reusable headers, resource actions, discovery controls, and shared RDF store context.

Changes:

  • Adds file-explorer header, provider, metadata, and styling components.
  • Introduces resource-action and discovery APIs.
  • Updates store context, exports, typings, tests, Storybook, and dependencies.
File Reviewed change
test/​unit/​index.test.ts Updates root export expectations.
src/​types/​custom-elements.d.ts Adds custom-element typings.
src/​styles/​theme.css Adds gray theme tokens.
src/​storybook/​store/​StorybookStore.ts Simplifies Storybook store creation.
src/​storybook/​components/​StorybookProvider.ts Provides the shared store context.
src/​lib/​store/​NoopStore.ts Adds a no-op store.
src/​lib/​store/​index.ts Exports store APIs.
src/​lib/​store/​context.ts Defines store context.
src/​lib/​resource-actions-menu.ts Adds resource action bindings.
src/​lib/​forms/​store/​StoreContext.ts Removes the old store context.
src/​lib/​forms/​store/​NoopStore.ts Removes the old no-op store.
src/​lib/​file-explorer/​relevant-panes.ts Resolves relevant panes.
src/​lib/​file-explorer/​context.ts Extends explorer context data.
src/​lib/​discovery/​index.ts Exports discovery APIs.
src/​lib/​discovery/​discovery.ts Adds discovery state management.
src/​index.ts Exports new public APIs.
src/​components/​resource-actions-menu/​ResourceActionsMenu.ts Implements the resource action menu.
src/​components/​resource-actions-menu/​ResourceActionsMenu.styles.css Styles the action menu.
src/​components/​resource-actions-menu/​index.ts Exports action-menu APIs.
src/​components/​resource-actions-menu/​helpers.ts Builds menu actions.
src/​components/​rdf-input/​RDFInput.ts Migrates to shared store context.
src/​components/​rdf-form/​RDFForm.ts Migrates to shared store context.
src/​components/​provider/​Provider.ts Provides the application store.
src/​components/​menu/​Menu.styles.css Adds configurable menu width.
src/​components/​menu-item/​MenuItem.styles.css Adds configurable item styling.
src/​components/​file-explorer-header/​types.ts Defines header metadata types.
src/​components/​file-explorer-header/​metadata.ts Adds metadata utilities.
src/​components/​file-explorer-header/​index.ts Exports header components.
src/​components/​file-explorer-header/​FileExplorerProvider.ts Provides header and pane context.
src/​components/​file-explorer-header/​FileExplorerProvider.styles.css Styles the provider layout.
src/​components/​file-explorer-header/​FileExplorerHeaderSummary.ts Renders resource summaries.
src/​components/​file-explorer-header/​FileExplorerHeaderSummary.styles.css Styles resource summaries.
src/​components/​file-explorer-header/​FileExplorerHeaderControls.ts Implements header controls.
src/​components/​file-explorer-header/​FileExplorerHeaderControls.styles.css Styles header controls.
src/​components/​file-explorer-header/​FileExplorerHeader.ts Implements metadata loading and header composition.
src/​components/​file-explorer-header/​FileExplorerHeader.styles.css Styles the header container.
package.json Bumps the package version.
package-lock.json Updates locked dependencies and metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +4 to +6
import 'solid-ui/components/button'
import 'solid-ui/components/menu'
import 'solid-ui/components/menu-item'
Comment on lines +21 to +22
if (filteredPanes.length === 0) {
return relevantPaneCandidates.length > 0 ? [relevantPaneCandidates[0]] : []
Comment on lines +32 to +34
return firstRelevantPaneIndex < firstFilteredPaneIndex
? [relevantPaneCandidates[0]].concat(filteredPanes)
: filteredPanes
Comment on lines +74 to +81
const metadata = await solidLogicSingleton.resource.fetchMetadata(sym(this.fileExplorerContext.subjectUri))
this.responseMetadata = {
modified: metadata.modified,
isPublic: metadata.access.isPublic,
canEdit: metadata.access.canEdit,
canDelete: metadata.access.canDelete,
aclUri: metadata.aclUri
}
Comment on lines +79 to +82
if (this.paneIcon !== undefined && this._resolvedPaneIconFor !== this.paneIcon) {
this._resolvedPaneIconFor = this.paneIcon
this.resolvePaneIcon()
}
Comment on lines +210 to +213
const subject = store.sym(this.subjectUri)
const menuItems = await this.getPaneItems(subject, this.context as DataBrowserContext, this.relevantPanes)

this.menuItems = menuItems
Comment on lines +41 to +55
visibleItems.push({
kind: 'custom',
label: options.discoverPublicly ? 'Undiscover Publicly' : 'Discover Publicly',
icon: createDiscoveryIcon('icon-lucide-globe'),
action: options.handleDiscoverPublicClick ?? (() => {
}),
})

visibleItems.push({
kind: 'custom',
label: options.discoverPrivately ? 'Undiscover Privately' : 'Discover Privately',
icon: createDiscoveryIcon('icon-lucide-lock-keyhole'),
action: options.handleDiscoverPrivateClick ?? (() => {
}),
})

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants