CI / build (push) Failing after 6m2s
Introduce a Node build system for minified CSS/JS with content hashes, add PWA support, i18n helpers, accessibility improvements, and more translatable strings. Move theme configuration from bookmarks to localStorage, add Playwright tests, and set up CI workflows.
129 lines
6.7 KiB
HTML
129 lines
6.7 KiB
HTML
<title>{$pagetitle}</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<meta name="referrer" content="same-origin">
|
|
<link rel="icon" type="image/png" href="{$base_path}/{function="ltrim($asset_path, '/')"}/img/favicon.png">
|
|
<link rel="manifest" href="{$base_path}/{function="ltrim($asset_path, '/')"}/manifest.json">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
|
<meta name="apple-mobile-web-app-title" content="Shaarli Pro">
|
|
<link rel="apple-touch-icon" href="{$base_path}/{function="ltrim($asset_path, '/')"}/img/icons/icon-192x192.png">
|
|
<link rel="alternate" type="application/rss+xml" href="{$feedurl}?do=rss{$searchcrits}#" title="RSS Feed" />
|
|
<link rel="alternate" type="application/atom+xml" href="{$feedurl}?do=atom{$searchcrits}#" title="ATOM Feed" />
|
|
<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#" title="Shaarli search - {$shaarlititle}" />
|
|
|
|
<!-- Prevent dark mode flash (FOUC) - must run before CSS loads -->
|
|
<script>
|
|
(function() {
|
|
// Load theme preferences from localStorage to prevent FOUC
|
|
var themeMode = localStorage.getItem('theme') ||
|
|
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
|
var themeId = localStorage.getItem('shaarit_theme_id') || 'DEFAULT';
|
|
|
|
// Apply persisted theme config (saved by the theme picker)
|
|
var storedConfig = localStorage.getItem('shaarit_themes_config');
|
|
if (storedConfig) {
|
|
try {
|
|
var config = JSON.parse(storedConfig);
|
|
if (config.default) themeId = config.default;
|
|
if (config.mode) themeMode = config.mode;
|
|
} catch(e) {}
|
|
}
|
|
|
|
// Disable light mode for dark-only themes
|
|
var darkOnlyThemes = ['LINEAR', 'SPOTIFY', 'NOTION', 'DISCORD', 'DRACULA', 'ONE_DARK_PRO', 'TOKYO_NIGHT', 'NORD', 'NIGHT_OWL', 'ANTHRACITE', 'CYBERPUNK', 'NAVY_ELEGANCE', 'EARTHY'];
|
|
if (darkOnlyThemes.indexOf(themeId) !== -1) {
|
|
themeMode = 'dark';
|
|
}
|
|
|
|
if (themeMode === 'dark') {
|
|
document.documentElement.setAttribute('data-theme', 'dark');
|
|
} else {
|
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
}
|
|
document.documentElement.setAttribute('data-theme-id', themeId);
|
|
|
|
if (themeMode === 'dark') {
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var mc = document.querySelector('meta[name="theme-color"]');
|
|
if (mc) mc.setAttribute('content', '#1e293b');
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<!-- Professional Theme CSS (minified build) -->
|
|
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/style.min.css?v={$version_hash}" />
|
|
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/themes.min.css?v={$version_hash}" />
|
|
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/custom_views.min.css?v={$version_hash}" />
|
|
{if="$pageName=='editlink' || $pageName=='addlink' || $pageName=='editlinkbatch'"}
|
|
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/awesomplete.min.css?v={$version_hash}" />
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/awesomplete.min.js?v={$version_hash}" defer></script>
|
|
{/if}
|
|
|
|
{if="$pageName=='editlink' || $pageName=='editlinkbatch' || ($pageName=='linklist' && isset($search_tags) && preg_match('/(^|[\s,])note([\s,]|$)/i', (string) $search_tags))"}
|
|
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
|
|
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/theme/toastui-editor-dark.min.css" />
|
|
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js" defer></script>
|
|
{/if}
|
|
|
|
<!-- Preconnect to external domains for performance -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin>
|
|
|
|
<!-- Google Fonts (loaded here instead of @import in CSS to avoid render block) -->
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
|
|
<!-- Icons (Material Design Icons) -->
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.2.96/css/materialdesignicons.min.css" crossorigin="anonymous">
|
|
|
|
<!-- Theme Color -->
|
|
<meta name="theme-color" content="#2563eb">
|
|
|
|
<!-- Plugins CSS -->
|
|
{loop="$plugins_includes.css_files"}
|
|
<link type="text/css" rel="stylesheet" href="{$base_path}/{function="ltrim($value, '/')"}?v=1.0.1" />
|
|
{/loop}
|
|
|
|
{if="is_file('data/user.css')"}
|
|
<link type="text/css" rel="stylesheet" href="/data/user.css?v=1.0.1" />
|
|
{/if}
|
|
|
|
<script>
|
|
var shaarli = {
|
|
basePath: '{$base_path}',
|
|
rootPath: '{$root_path}',
|
|
assetPath: '{$base_path}{$asset_path}',
|
|
token: '{$token}',
|
|
isAuth: (function(){/*{if="$is_logged_in"}*/return true;/*{else}*/return false;/*{/if}*/})(),
|
|
pageName: '{$pageName}',
|
|
visibility: '{$visibility}',
|
|
untaggedonly: (function(){/*{if="$untaggedonly"}*/return true;/*{else}*/return false;/*{/if}*/})()
|
|
};
|
|
</script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/i18n.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/a11y.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/shaarit-rules.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/theme.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/navigation.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/search.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/bulk-actions.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/script.min.js?v={$version_hash}" defer></script>
|
|
<script src="{$base_path}/{function="ltrim($asset_path, '/')"}/dist/custom_views.min.js?v={$version_hash}" defer></script>
|
|
|
|
<!-- Register PWA service worker -->
|
|
<script>
|
|
(function() {
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('{$base_path}/{function="ltrim($asset_path, '/')"}/service-worker.js')
|
|
.then(function() { /* service worker registered */ })
|
|
.catch(function() { /* registration failed, continue normally */ });
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
{if="file_exists('tpl/shaarli-pro/extra.html')"}
|
|
{include="extra"}
|
|
{/if}
|