wrolpi/app/public/index.html

95 lines
4.2 KiB
HTML
Raw Permalink Normal View History

<!DOCTYPE html>
Fixing changes before merge. Moving FilesRefreshButton and DirectoryRefreshButton out of browser file. Moving file fetching tino FileBrowser. Removing sub-folders from Files display when any parent folder is clicked. Using closed captioning for vtt/srt file icon. Using my own react-semantic-toasts-2 to use toasts in Node 18. Fixing bug where more than the last page was displayed. Upgrading yt-dlp. Fixing sub-folder file selection. Adding rowKey to SortableTable to give React a key for each row. Renaming key to path. Removing duplicate urls. Unifying file modals. Displaying modals for image and text files. Handling refresh loading in FileBrowser. Creating refreshing_directory flag. Removing accidental commit. Sorting by url_count. Using SortableTable on Domains page. Using SortableTable for Channels page. Created new FileBrowser which allows browsing of files in the media directory. Using Node 18 in pi-gen. Creating new FileBrowser to replace outdated react-keyed-file-browser. Returning mimetype with file list. Do not display 'Do not download' on Channel download in Dashboard. Allowing null channel download frequency so user can stop downloading a channel. Bumping version for Node 18. Using my own semantic-ui-offline to avoid pulling Google fonts. Upgrading app docker container to use Node 18. This requires the removal of several npm packages. File browser will require re-write. It now pulls fonts from Google, this will need to be fixed. Testing DownloadsToggle click. Testing trinary states of DownloadsToggle. Installing @testing-library/user-event for testing App.
2023-01-31 18:08:07 -07:00
<html lang="en" style="height: 100%">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta
name="description"
content="The WROLPI webapp"
/>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png">
<link rel="mask-icon" href="%PUBLIC_URL%/safari-pinned-tab.svg" color="#5bbad5">
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>WROLPi: Create your own off-grid library</title>
<script>
/*
ui: media filtering is a per-theme setting, not a night-mode hardcode Filtering media was keyed on `data-theme="night"`, which made it a property of the theme that no user could turn off. Some people want their media tinted to match the interface; some want to see the actual image. A theme now declares a filter and whether it starts on, and the user decides: night night-red on by default. An unfiltered thumbnail undoes dark adaptation, which is the whole point of the mode. amber amber-mono off by default. Amber is a look, not a night-vision aid, so media keeps its real colors until asked for. light - no filter offered, so no toggle is shown. dark - The choice is stored per theme, so wanting amber's tint says nothing about wanting night's. The toggle lives in the theme picker, which puts it on the Settings page and in the gallery at once. Mechanically the rules now key on a `data-media-filter` attribute rather than `data-theme`: a rule keyed on the theme could not be turned off. index.html stamps that attribute before first paint alongside data-theme -- without it, night mode paints a screen of unfiltered thumbnails while the bundle arrives over a hotspot, costing the user the adaptation the theme exists to protect. Tests cover both the attribute rule and the fact that the inline script's duplicated ids and defaults still agree with names.ts. The amber matrix is the same luminance collapse tinted to #ff9500 (red full, green 0.584, blue zero) with a gentler gamma than night's: amber carries far more luminance and clips to a flat wash otherwise. The gallery gains a Media filtering section showing the WROLPi logo filtered, beside an unfiltered copy that opts out with `night-unfiltered`. That copy is behind a click on purpose -- an unfiltered image is a bright patch, and night mode should not spring one on someone reading in the dark. ui-design.md gains the media filtering contract it never got in Phase 0, including the note that a Phase 3 custom theme names an existing filter id and cannot ship its own matrix, since that would be code rather than data.
2026-07-30 08:51:28 -06:00
Stamp the saved theme, and the media filter it resolves to, on <html> before first
paint. ThemeProvider sets the same attributes once React mounts, but the bundle can
take a while to arrive over a hotspot — without this the page would paint in the wrong
theme first, and in night mode a flash of unfiltered thumbnails would cost the user the
dark adaptation the theme exists to protect.
Keep the storage keys, theme names, and filter defaults in sync with
src/themes/names.ts.
*/
(function () {
var theme = 'light';
ui: night mode actually filters media, and fix three picker icons Addresses the automated review on #583; all three were real. The night filter only applied to elements tagged `.media`, and nothing in the app carried that class - so selecting Night filtered the interface but left every video, thumbnail, PDF and map full-colour, which is precisely the thing the mode exists to prevent. The Settings copy promised otherwise, so it was also wrong. It now targets the element types instead of an opt-in class, because night mode has to fail safe: a library of thousands of files reaches the screen through many components, and one that forgot to opt in would undo half an hour of dark adaptation. `.media` still works for wrappers that must be filtered as a unit, and `.night-unfiltered` opts out. The filter is restated on `:fullscreen`, which a filter on an ancestor stops reaching. Verified on the videos page: all 25 media elements filtered. Three of the five theme choices rendered a fallback glyph and logged errors, because the icon map was built by grepping literal name='...' strings and the navigation picker passes its icon through a variable. Adds sun, moon and lightbulb, plus a test asserting every theme choice resolves to a real icon. The pre-paint script wrapped the `matchMedia` fallback in the same try as the storage read, so a device with storage blocked painted light even when it prefers dark - recreating the flash the script exists to prevent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 19:57:06 -06:00
var saved = null;
// Only the storage read can throw (blocked cookies/storage). Keep the try
// around just that, so a device that prefers dark still gets dark.
try {
ui: night mode actually filters media, and fix three picker icons Addresses the automated review on #583; all three were real. The night filter only applied to elements tagged `.media`, and nothing in the app carried that class - so selecting Night filtered the interface but left every video, thumbnail, PDF and map full-colour, which is precisely the thing the mode exists to prevent. The Settings copy promised otherwise, so it was also wrong. It now targets the element types instead of an opt-in class, because night mode has to fail safe: a library of thousands of files reaches the screen through many components, and one that forgot to opt in would undo half an hour of dark adaptation. `.media` still works for wrappers that must be filtered as a unit, and `.night-unfiltered` opts out. The filter is restated on `:fullscreen`, which a filter on an ancestor stops reaching. Verified on the videos page: all 25 media elements filtered. Three of the five theme choices rendered a fallback glyph and logged errors, because the icon map was built by grepping literal name='...' strings and the navigation picker passes its icon through a variable. Adds sun, moon and lightbulb, plus a test asserting every theme choice resolves to a real icon. The pre-paint script wrapped the `matchMedia` fallback in the same try as the storage read, so a device with storage blocked painted light even when it prefers dark - recreating the flash the script exists to prevent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 19:57:06 -06:00
saved = localStorage.getItem('color-scheme');
} catch (e) {
ui: night mode actually filters media, and fix three picker icons Addresses the automated review on #583; all three were real. The night filter only applied to elements tagged `.media`, and nothing in the app carried that class - so selecting Night filtered the interface but left every video, thumbnail, PDF and map full-colour, which is precisely the thing the mode exists to prevent. The Settings copy promised otherwise, so it was also wrong. It now targets the element types instead of an opt-in class, because night mode has to fail safe: a library of thousands of files reaches the screen through many components, and one that forgot to opt in would undo half an hour of dark adaptation. `.media` still works for wrappers that must be filtered as a unit, and `.night-unfiltered` opts out. The filter is restated on `:fullscreen`, which a filter on an ancestor stops reaching. Verified on the videos page: all 25 media elements filtered. Three of the five theme choices rendered a fallback glyph and logged errors, because the icon map was built by grepping literal name='...' strings and the navigation picker passes its icon through a variable. Adds sun, moon and lightbulb, plus a test asserting every theme choice resolves to a real icon. The pre-paint script wrapped the `matchMedia` fallback in the same try as the storage read, so a device with storage blocked painted light even when it prefers dark - recreating the flash the script exists to prevent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 19:57:06 -06:00
saved = null;
}
if (saved === 'light' || saved === 'dark' || saved === 'night' || saved === 'amber') {
theme = saved;
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
// `system`, unset, or written by an older version.
theme = 'dark';
}
document.documentElement.setAttribute('data-theme', theme);
ui: media filtering is a per-theme setting, not a night-mode hardcode Filtering media was keyed on `data-theme="night"`, which made it a property of the theme that no user could turn off. Some people want their media tinted to match the interface; some want to see the actual image. A theme now declares a filter and whether it starts on, and the user decides: night night-red on by default. An unfiltered thumbnail undoes dark adaptation, which is the whole point of the mode. amber amber-mono off by default. Amber is a look, not a night-vision aid, so media keeps its real colors until asked for. light - no filter offered, so no toggle is shown. dark - The choice is stored per theme, so wanting amber's tint says nothing about wanting night's. The toggle lives in the theme picker, which puts it on the Settings page and in the gallery at once. Mechanically the rules now key on a `data-media-filter` attribute rather than `data-theme`: a rule keyed on the theme could not be turned off. index.html stamps that attribute before first paint alongside data-theme -- without it, night mode paints a screen of unfiltered thumbnails while the bundle arrives over a hotspot, costing the user the adaptation the theme exists to protect. Tests cover both the attribute rule and the fact that the inline script's duplicated ids and defaults still agree with names.ts. The amber matrix is the same luminance collapse tinted to #ff9500 (red full, green 0.584, blue zero) with a gentler gamma than night's: amber carries far more luminance and clips to a flat wash otherwise. The gallery gains a Media filtering section showing the WROLPi logo filtered, beside an unfiltered copy that opts out with `night-unfiltered`. That copy is behind a click on purpose -- an unfiltered image is a bright patch, and night mode should not spring one on someone reading in the dark. ui-design.md gains the media filtering contract it never got in Phase 0, including the note that a Phase 3 custom theme names an existing filter id and cannot ship its own matrix, since that would be code rather than data.
2026-07-30 08:51:28 -06:00
// Which filter each theme uses, and whether it applies unless the user says otherwise.
var filters = {night: 'night-red', amber: 'amber-mono'};
var defaults = {night: true, amber: false};
if (filters[theme]) {
var enabled = defaults[theme];
try {
var overrides = JSON.parse(localStorage.getItem('media-filter') || '{}');
if (typeof overrides[theme] === 'boolean') {
enabled = overrides[theme];
}
} catch (e) {
// Blocked storage or malformed JSON: fall back to the theme's default.
}
if (enabled) {
document.documentElement.setAttribute('data-media-filter', filters[theme]);
}
}
})();
</script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>