Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
88d3011
added icon base size
SharonStrats Mar 16, 2026
ccd1e51
small icon
SharonStrats Mar 16, 2026
ba3436f
background row colors
SharonStrats Mar 16, 2026
b0788fb
xs icon size
SharonStrats Mar 16, 2026
da22f87
xl icon size
SharonStrats Mar 16, 2026
19eef55
xxs icon size
SharonStrats Mar 16, 2026
d01ee7f
updated css var
timea-solid Mar 23, 2026
270b14f
Merge pull request #343 from SolidOS/refactor/styles-separateCSS
timea-solid Mar 23, 2026
85f0bd5
Initial plan
Copilot Mar 23, 2026
d6d4911
Add missing dark theme CSS custom properties to dark.css
Copilot Mar 23, 2026
2032e76
Merge pull request #344 from SolidOS/copilot/sub-pr-342
timea-solid Mar 23, 2026
4c43118
Merge branch 'main' into profileEditA11y
timea-solid Mar 23, 2026
d400aa8
Merge branch 'profileEditA11y' of https://github.com/SolidOS/mashlib …
timea-solid Mar 23, 2026
bf7377e
removed not in use dump function
timea-solid Mar 23, 2026
e00b513
added preparations for mobile
timea-solid Mar 23, 2026
97728df
cnosolidation of mobile options
timea-solid Mar 24, 2026
323e81c
SolidOS app title
timea-solid Mar 24, 2026
1043c5c
removed old table structure form databrowser.html
timea-solid Mar 24, 2026
0e4918f
removed old table structure form databrowser.html
timea-solid Mar 24, 2026
3a9b087
SolidOS app title
timea-solid Mar 24, 2026
476a36c
cnosolidation of mobile options
timea-solid Mar 24, 2026
d294201
some merge issues
timea-solid Mar 24, 2026
4723132
merge main
timea-solid Mar 24, 2026
7d61e49
merge main
timea-solid Mar 24, 2026
5fd8127
Update README.md
timea-solid Mar 24, 2026
ec908b9
Update src/styles/mash.css
timea-solid Mar 24, 2026
c5ed774
Update src/styles/mash.css
timea-solid Mar 24, 2026
641de88
Update src/styles/mash.css
timea-solid Mar 24, 2026
5a6f721
Update src/index.ts
timea-solid Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ A colorful dependency tree can be seen [here](https://github.com/solidos/solidos
- [Developing mashlib](#developing-mashlib)
- [Goals](#goals)
- [Typical uses](#typical-uses)
- [Generative AI usage](#generative-ai-usage)

### Documentation

Expand All @@ -36,6 +37,8 @@ A colorful dependency tree can be seen [here](https://github.com/solidos/solidos
- [Solid-ui & Solid-logic related:](#solid-ui--solid-logic-related)
- [The databrowser hack: upgrading your browser](#the-databrowser-hack-upgrading-your-browser)

### [Generative AI usage](#generative-ai-usage)

## Developing mashlib

As part of the SolidOS stack, mashlib can be developed locally by setting up the SolidOS code. Read more about that on the [SolidOS Readme](https://github.com/solidos/solidos#-getting-started-with-the-solidos-code).
Expand Down Expand Up @@ -151,3 +154,11 @@ The mashlib part of SolidOS Databrowser Frontend is *read-write;* that is, the u

A major limitation of this data browser hack is that current web browsers are made to distrust any code loaded from one domain that uses data from another domain. This makes it hard, strangely complicated, and sometimes impossible to do some things.

## Generative AI usage
The SolidOS team is using GitHub Copilot integrated in Visual Studio Code.
We have added comments in the code to make it explicit which parts are 100% written by AI.

### Prompt usage history:
* Auto model: Looking at these 2 files (databrowser.html and index.ts), I want to redesign mashlib and underlying panes. I have a design for web and one for mobile. How would I go about making sure I can also have a mobile version?

* Claude-Opes 4.6: I don't think this is correct. Mashlib is bundling together all the panes. I do not need to add mashlib.layout or theme to the globals. I can just call the render of each pane with an interface of values or?
768 changes: 405 additions & 363 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@
"rdflib": "^2.3.6",
"solid-logic": "^4.0.6",
"solid-panes": "^4.2.4",
"solid-ui": "^3.0.5"
"solid-ui": "^3.0.5",
"pane-registry": "^3.0.2"
},
"overrides": {
"rdflib": "$rdflib",
"solid-logic": "$solid-logic",
"solid-ui": "$solid-ui"
"solid-ui": "$solid-ui",
"pane-registry": "$pane-registry"
},
"devDependencies": {
"@babel/cli": "^7.28.6",
Expand Down
75 changes: 54 additions & 21 deletions src/databrowser.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,65 @@
<html>
<head>
<meta charset="utf-8"/>
<title><%= htmlWebpackPlugin.options.title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
<title>SolidOS</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
panes.runDataBrowser()
})
</script>
</head>
<body id="PageBody">
<!-- solid-panes' OutlineManager injects into this element -->
<header id="PageHeader" role="banner"></header>
<main id="mainContent" tabindex="-1">
<div class="TabulatorOutline" id="DummyUUID">
<table id="outline">
<thead>
<tr>
<th id="outlineHeader" scope="col"></th>
<!-- Add more <th> as needed for columns -->
</tr>
</thead>
<tbody>
<!-- Table rows injected by JS -->
</tbody>
</table>
<div id="GlobalDashboard" aria-label="Global Dashboard"></div>
</div>
</main>
<footer id="PageFooter" role="contentinfo"></footer>
<body id="PageBody" data-app-shell="databrowser">

<!-- Skip-navigation link (accessibility) -->
<a href="#MainContent" class="skip-link">Skip to main content</a>

<!-- Header — populated by solid-ui initHeader() -->
<header id="PageHeader" role="banner">
<!--
solid-ui injects: logo, address/URI bar, user menu, help menu.
The nav bar inside should get role="navigation" and aria-label="Main".
-->
</header>

<!-- Main content area — single visible region at a time -->
<main id="MainContent" role="main" tabindex="-1" aria-live="polite">

<!--
Outline view: the primary RDF-subject browser.
Replaces the old <table id="outline"> with a semantic <section>.
JS appends property-table <div>s (not <tr>s) here.
-->
<section
id="OutlineView"
class="outline-view"
aria-label="Resource browser"
>
<!--
Pane icon tray (nav) and pane content are injected here by
OutlineManager.GotoSubject / propertyTable / outlineExpand.
Each subject block is a <article class="subject-block">.
-->
</section>

<!--
Global Dashboard: preferences, profile, contacts, etc.
Hidden by default; toggled by showDashboard / closeDashboard.
-->
<section
id="GlobalDashboard"
class="global-dashboard"
aria-label="Dashboard"
hidden
>
<!-- globalAppTabs appends tab widget here -->
</section>

</main>

<!-- Footer — populated by solid-ui initFooter() -->
<footer id="PageFooter" role="contentinfo">
<!-- solid-ui injects: "Powered by Solid" link -->
</footer>
</body>
</html>
86 changes: 45 additions & 41 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
import * as $rdf from 'rdflib'
import * as panes from 'solid-panes'
import { authn, solidLogicSingleton, authSession, store } from 'solid-logic'
import { layout } from './layout'
import { theme } from './theme'
import type { RenderEnvironment } from 'pane-registry'

Check failure on line 6 in src/index.ts

View workflow job for this annotation

GitHub Actions / build (22)

Module '"pane-registry"' has no exported member 'RenderEnvironment'.

Check failure on line 6 in src/index.ts

View workflow job for this annotation

GitHub Actions / build (24)

Module '"pane-registry"' has no exported member 'RenderEnvironment'.
import versionInfo from './versionInfo'
import './styles/mash.css'

const global: any = window

// Theme Management
const initializeTheme = () => {
const savedTheme = localStorage.getItem('mashlib-theme')
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const theme = savedTheme || (prefersDark ? 'dark' : 'light')
// Build a snapshot of the current render environment
const buildRenderEnvironment = (): RenderEnvironment => ({
layout: layout.get(),
layoutPreference: layout.getPreference(),
inputMode: layout.getInputMode(),
theme: theme.get(),
viewport: layout.getViewport()
})

// Inject or update the environment on the pane context
const syncEnvironmentToContext = () => {

if (theme === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark')
} else {
document.documentElement.removeAttribute('data-theme')
const outliner = panes.getOutliner(document) as any

if (!outliner) {
console.warn('outliner not ready yet')
return
}
}

const setTheme = (theme: 'light' | 'dark') => {
if (theme === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark')
} else {
document.documentElement.removeAttribute('data-theme')
if (!outliner.context) {
console.warn('outliner.context missing: creating fallback context')
outliner.context = {}
}
localStorage.setItem('mashlib-theme', theme)
}

const getTheme = (): 'light' | 'dark' => {
return document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
outliner.context.environment = buildRenderEnvironment()
}

// Initialize theme on load
initializeTheme()
// Initialize theme and layout
theme.init()
layout.init()

// Keep environment in sync on layout/theme changes
window.addEventListener('mashlib:layoutchange', syncEnvironmentToContext)
Comment on lines +39 to +44
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

layout.init() dispatches the mashlib:layoutchange event immediately (during module init), but syncEnvironmentToContext() depends on an outliner created later by panes.initMainPage. This means the initial page load will reliably emit console.warn('outliner not ready yet'). Consider delaying registration of the layoutchange listener until after initMainPage (or making syncEnvironmentToContext silent until the first successful sync) to avoid noisy logs.

Copilot uses AI. Check for mistakes.

global.$rdf = $rdf
global.panes = panes
Expand All @@ -43,14 +51,7 @@
store,
solidLogicSingleton
}
global.mashlib = {
versionInfo,
theme: {
set: setTheme,
get: getTheme,
init: initializeTheme
}
}
global.mashlib = { versionInfo }

global.panes.runDataBrowser = function (uri?:string|$rdf.NamedNode|null) {
// Set up cross-site proxy
Expand All @@ -67,11 +68,20 @@
console.error('Failed to add web monetization tag to page header')
}

window.addEventListener('load', syncEnvironmentToContext)

// Authenticate the user
authn.checkUser().then(function (_profile: any) {
const mainPage = panes.initMainPage(solidLogicSingleton.store, uri)
return mainPage
})
authn.checkUser()
.then(() => panes.initMainPage(solidLogicSingleton.store, uri))
.then(() => {
// Inject render environment into pane context after outliner exists
syncEnvironmentToContext()
window.requestAnimationFrame(syncEnvironmentToContext)
})
.catch((err: any) => {
console.error('runDataBrowser failed', err)
})

}

window.onpopstate = function (_event: any) {
Expand All @@ -84,13 +94,7 @@
)
}

// It's not clear where this function is used, so unfortunately we cannot remove it:
function dump (msg: string[]) {
console.log(msg.slice(0, -1))
}

global.dump = dump

export {
versionInfo
versionInfo,
buildRenderEnvironment
}
107 changes: 107 additions & 0 deletions src/layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* generated by AI - see readme for details*/
import type { LayoutMode, LayoutPreference } from 'pane-registry'

Check failure on line 2 in src/layout.ts

View workflow job for this annotation

GitHub Actions / build (22)

Module '"pane-registry"' has no exported member 'LayoutPreference'.

Check failure on line 2 in src/layout.ts

View workflow job for this annotation

GitHub Actions / build (22)

Module '"pane-registry"' has no exported member 'LayoutMode'.

Check failure on line 2 in src/layout.ts

View workflow job for this annotation

GitHub Actions / build (24)

Module '"pane-registry"' has no exported member 'LayoutPreference'.

Check failure on line 2 in src/layout.ts

View workflow job for this annotation

GitHub Actions / build (24)

Module '"pane-registry"' has no exported member 'LayoutMode'.

const LAYOUT_STORAGE_KEY = 'mashlib-layout'
const MOBILE_BREAKPOINT_PX = 768

const getStoredLayoutPreference = (): LayoutPreference => {
const storedLayout = localStorage.getItem(LAYOUT_STORAGE_KEY)

if (storedLayout === 'mobile' || storedLayout === 'desktop' || storedLayout === 'auto') {
return storedLayout
}

return 'auto'
}

const resolveAutomaticLayout = (): LayoutMode => {
return window.innerWidth <= MOBILE_BREAKPOINT_PX ? 'mobile' : 'desktop'
}

const applyLayoutAttributes = (layout: LayoutMode, preference: LayoutPreference) => {
const root = document.documentElement
const inputMode = window.matchMedia('(pointer: coarse)').matches ? 'touch' : 'pointer'

root.setAttribute('data-layout', layout)
root.setAttribute('data-layout-preference', preference)
root.setAttribute('data-input-mode', inputMode)
root.style.setProperty('--app-height', `${window.innerHeight}px`)

window.dispatchEvent(new CustomEvent('mashlib:layoutchange', {
detail: {
inputMode,
layout,
preference,
viewport: {
height: window.innerHeight,
width: window.innerWidth
}
}
}))
}

const updateLayout = (preference: LayoutPreference = getStoredLayoutPreference()): LayoutMode => {
const layout = preference === 'auto' ? resolveAutomaticLayout() : preference
applyLayoutAttributes(layout, preference)
return layout
}

const setLayoutPreference = (preference: LayoutPreference): LayoutMode => {
if (preference === 'auto') {
localStorage.removeItem(LAYOUT_STORAGE_KEY)
} else {
localStorage.setItem(LAYOUT_STORAGE_KEY, preference)
}

return updateLayout(preference)
}

const getLayoutPreference = (): LayoutPreference => {
return getStoredLayoutPreference()
}

const getLayoutMode = (): LayoutMode => {
return (document.documentElement.getAttribute('data-layout') as LayoutMode) || resolveAutomaticLayout()
}

const initializeLayout = () => {
let resizeFrame = 0
const syncLayout = () => {
updateLayout()
}

const onResize = () => {
if (resizeFrame) {
window.cancelAnimationFrame(resizeFrame)
}

resizeFrame = window.requestAnimationFrame(() => {
resizeFrame = 0
syncLayout()
})
}

syncLayout()
window.addEventListener('resize', onResize)

window.matchMedia('(pointer: coarse)').addEventListener('change', syncLayout)
window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT_PX}px)`).addEventListener('change', syncLayout)
}

const getInputMode = (): 'touch' | 'pointer' => {
return window.matchMedia('(pointer: coarse)').matches ? 'touch' : 'pointer'
}

const getViewport = () => ({
width: window.innerWidth,
height: window.innerHeight
})

export const layout = {
get: getLayoutMode,
getInputMode,
getPreference: getLayoutPreference,
getViewport,
init: initializeLayout,
set: setLayoutPreference
}
Loading
Loading