Compare commits

..

2 Commits

Author SHA1 Message Date
3b3a40c771 chore(prettier): format templates
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-16 17:11:03 -04:00
f37bff365f chore(templates): prettier plugin & tables 2024-06-16 17:08:10 -04:00
28 changed files with 1860 additions and 1169 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ data/
build/
.direnv/
cover.html
node_modules

3
.prettierrc Normal file
View File

@ -0,0 +1,3 @@
{
"plugins": ["prettier-plugin-go-template"]
}

File diff suppressed because one or more lines are too long

55
package-lock.json generated Normal file
View File

@ -0,0 +1,55 @@
{
"name": "antholume",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "antholume",
"version": "1.0.0",
"devDependencies": {
"prettier-plugin-go-template": "^0.0.15"
}
},
"node_modules/prettier": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
"dev": true,
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-plugin-go-template": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/prettier-plugin-go-template/-/prettier-plugin-go-template-0.0.15.tgz",
"integrity": "sha512-WqU92E1NokWYNZ9mLE6ijoRg6LtIGdLMePt2C7UBDjXeDH9okcRI3zRqtnWR4s5AloiqyvZ66jNBAa9tmRY5EQ==",
"dev": true,
"dependencies": {
"ulid": "^2.3.0"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"prettier": "^3.0.0"
}
},
"node_modules/ulid": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz",
"integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==",
"dev": true,
"bin": {
"ulid": "bin/cli.js"
}
}
}
}

7
package.json Normal file
View File

@ -0,0 +1,7 @@
{
"name": "antholume",
"version": "1.0.0",
"devDependencies": {
"prettier-plugin-go-template": "^0.0.15"
}
}

View File

@ -3,6 +3,7 @@
pkgs.mkShell {
packages = with pkgs; [
go
nodejs
nodePackages.tailwindcss
python311Packages.grip
];

View File

@ -1,18 +1,26 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" />
<meta
name="viewport"
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style"
content="black-translucent" />
<meta name="theme-color"
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<meta
name="theme-color"
content="#F3F4F6"
media="(prefers-color-scheme: light)" />
<meta name="theme-color"
media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#1F2937"
media="(prefers-color-scheme: dark)" />
media="(prefers-color-scheme: dark)"
/>
<title>AnthoLume - {{ block "title" . }}{{ end }}</title>
<link rel="manifest" href="/manifest.json" />
<link rel="stylesheet" href="/assets/style.css" />
@ -32,7 +40,8 @@
html {
height: calc(100% + env(safe-area-inset-bottom));
padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
padding: env(safe-area-inset-top) env(safe-area-inset-right) 0
env(safe-area-inset-left);
}
main {
@ -85,8 +94,9 @@
/* ----------------------------- */
#mobile-nav-button span {
transform-origin: 5px 0px;
transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0),
background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0),
transition:
transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1),
background 0.5s cubic-bezier(0.77, 0.2, 0.05, 1),
opacity 0.55s ease;
}
@ -127,12 +137,15 @@
padding-top: env(safe-area-inset-top);
transform-origin: 0% 0%;
transform: translate(-100%, 0);
transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1.0);
transition: transform 0.5s cubic-bezier(0.77, 0.2, 0.05, 1);
}
@media (orientation: landscape) {
#menu {
transform: translate(calc(-1 * (env(safe-area-inset-left) + 100%)), 0);
transform: translate(
calc(-1 * (env(safe-area-inset-left) + 100%)),
0
);
}
}
</style>
@ -140,87 +153,161 @@
<body class="bg-gray-100 dark:bg-gray-800">
<div class="flex items-center justify-between w-full h-16">
<div id="mobile-nav-button" class="flex flex-col z-40 relative ml-6">
<input type="checkbox"
class="absolute lg:hidden z-50 -top-2 w-7 h-7 flex cursor-pointer opacity-0" />
<span class="lg:hidden bg-black w-7 h-0.5 z-40 mt-0.5 dark:bg-white"></span>
<span class="lg:hidden bg-black w-7 h-0.5 z-40 mt-1 dark:bg-white"></span>
<span class="lg:hidden bg-black w-7 h-0.5 z-40 mt-1 dark:bg-white"></span>
<div id="menu"
class="fixed -ml-6 h-full w-56 lg:w-48 bg-white dark:bg-gray-700 shadow-lg">
<input
type="checkbox"
class="absolute lg:hidden z-50 -top-2 w-7 h-7 flex cursor-pointer opacity-0"
/>
<span
class="lg:hidden bg-black w-7 h-0.5 z-40 mt-0.5 dark:bg-white"
></span>
<span
class="lg:hidden bg-black w-7 h-0.5 z-40 mt-1 dark:bg-white"
></span>
<span
class="lg:hidden bg-black w-7 h-0.5 z-40 mt-1 dark:bg-white"
></span>
<div
id="menu"
class="fixed -ml-6 h-full w-56 lg:w-48 bg-white dark:bg-gray-700 shadow-lg"
>
<div class="h-16 flex justify-end lg:justify-around">
<p class="text-xl font-bold dark:text-white text-right my-auto pr-8 lg:pr-0">AnthoLume</p>
<p
class="text-xl font-bold dark:text-white text-right my-auto pr-8 lg:pr-0"
>
AnthoLume
</p>
</div>
<div>
{{ $default := "flex items-center justify-start w-full p-2 pl-6 my-2 transition-colors duration-200 border-l-4" }}
{{ $inactive := "border-transparent text-gray-400 hover:text-gray-800 dark:hover:text-gray-100" }}
{{ $active := "border-purple-500 dark:text-white" }}
<a class="{{ $default }} {{ if eq .RouteName "home" }}{{ $active }}{{ else if true }}{{ $inactive }}{{ end }}"
href="/">
<a
class="{{ $default }} {{ if eq .RouteName "home" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/"
>
{{ template "svg/home" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Home</span>
</a>
<a class="{{ $default }} {{ if eq .RouteName "documents" }}{{ $active }}{{ else if true }}{{ $inactive }}{{ end }}"
href="/documents">
<a
class="{{ $default }} {{ if eq .RouteName "documents" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/documents"
>
{{ template "svg/documents" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Documents</span>
</a>
<a class="{{ $default }} {{ if eq .RouteName "progress" }}{{ $active }}{{ else if true }}{{ $inactive }}{{ end }}"
href="/progress">
<a
class="{{ $default }} {{ if eq .RouteName "progress" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/progress"
>
{{ template "svg/activity" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Progress</span>
</a>
<a class="{{ $default }} {{ if eq .RouteName "activity" }}{{ $active }}{{ else if true }}{{ $inactive }}{{ end }}"
href="/activity">
<a
class="{{ $default }} {{ if eq .RouteName "activity" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/activity"
>
{{ template "svg/activity" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Activity</span>
</a>
{{ if .Config.SearchEnabled }}
<a class="{{ $default }} {{ if eq .RouteName "search" }}{{ $active }}{{ else if true }}{{ $inactive }}{{ end }}"
href="/search">
<a
class="{{ $default }} {{ if eq .RouteName "search" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/search"
>
{{ template "svg/search" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Search</span>
</a>
{{ end }}
{{ if .Authorization.IsAdmin }}
<div class="flex flex-col gap-4 p-2 pl-6 my-2 transition-colors duration-200 border-l-4 {{ if hasPrefix .RouteName "admin" }}dark:text-white border-purple-500{{ else if true }}border-transparent text-gray-400{{ end }}">
<a href="/admin"
class="flex justify-start w-full {{ if not (hasPrefix .RouteName "admin") }}text-gray-400 hover:text-gray-800 dark:hover:text-gray-100{{ end }}">
<div
class="flex flex-col gap-4 p-2 pl-6 my-2 transition-colors duration-200 border-l-4 {{ if hasPrefix .RouteName "admin" }}
dark:text-white border-purple-500
{{ else if true }}
border-transparent text-gray-400
{{ end }}"
>
<a
href="/admin"
class="flex justify-start w-full {{ if not (hasPrefix .RouteName "admin") }}
text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
{{ end }}"
>
{{ template "svg/settings" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Admin</span>
</a>
{{ if hasPrefix .RouteName "admin" }}
<a href="/admin"
<a
href="/admin"
style="padding-left: 1.75em"
class="flex justify-start w-full {{ if not (eq .RouteName "admin") }}text-gray-400 hover:text-gray-800 dark:hover:text-gray-100{{ end }}">
class="flex justify-start w-full {{ if not (eq .RouteName "admin") }}
text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
{{ end }}"
>
<span class="mx-4 text-sm font-normal">General</span>
</a>
<a href="/admin/import"
<a
href="/admin/import"
style="padding-left: 1.75em"
class="flex justify-start w-full {{ if not (eq .RouteName "admin-import") }}text-gray-400 hover:text-gray-800 dark:hover:text-gray-100{{ end }}">
class="flex justify-start w-full {{ if not (eq .RouteName "admin-import") }}
text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
{{ end }}"
>
<span class="mx-4 text-sm font-normal">Import</span>
</a>
<a href="/admin/users"
<a
href="/admin/users"
style="padding-left: 1.75em"
class="flex justify-start w-full {{ if not (eq .RouteName "admin-users") }}text-gray-400 hover:text-gray-800 dark:hover:text-gray-100{{ end }}">
class="flex justify-start w-full {{ if not (eq .RouteName "admin-users") }}
text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
{{ end }}"
>
<span class="mx-4 text-sm font-normal">Users</span>
</a>
<a href="/admin/logs"
<a
href="/admin/logs"
style="padding-left: 1.75em"
class="flex justify-start w-full {{ if not (eq .RouteName "admin-logs") }}text-gray-400 hover:text-gray-800 dark:hover:text-gray-100{{ end }}">
class="flex justify-start w-full {{ if not (eq .RouteName "admin-logs") }}
text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
{{ end }}"
>
<span class="mx-4 text-sm font-normal">Logs</span>
</a>
{{ end }}
</div>
{{ end }}
</div>
<a class="flex flex-col gap-2 justify-center items-center p-6 w-full absolute bottom-0 text-black dark:text-white"
<a
class="flex flex-col gap-2 justify-center items-center p-6 w-full absolute bottom-0 text-black dark:text-white"
target="_blank"
href="https://gitea.va.reichard.io/evan/AnthoLume">
<svg xmlns="http://www.w3.org/2000/svg"
href="https://gitea.va.reichard.io/evan/AnthoLume"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="text-black dark:text-white"
height="20"
viewBox="0 0 219 92"
fill="currentColor">
fill="currentColor"
>
<defs>
<clipPath id="a">
<path d="M159 .79h25V69h-25Zm0 0" />
@ -232,49 +319,77 @@
<path d="M0 .79h92V92H0Zm0 0" />
</clipPath>
</defs>
<path style="stroke: none; fill-rule: nonzero; fill-opacity: 1" d="M130.871 31.836c-4.785 0-8.351 2.352-8.351 8.008 0 4.261 2.347 7.222 8.093 7.222 4.871 0 8.18-2.867 8.18-7.398 0-5.133-2.961-7.832-7.922-7.832Zm-9.57 39.95c-1.133 1.39-2.262 2.87-2.262 4.612 0 3.48 4.434 4.524 10.527 4.524 5.051 0 11.926-.352 11.926-5.043 0-2.793-3.308-2.965-7.488-3.227Zm25.761-39.688c1.563 2.004 3.22 4.789 3.22 8.793 0 9.656-7.571 15.316-18.536 15.316-2.789 0-5.312-.348-6.879-.785l-2.87 4.613 8.526.52c15.059.96 23.934 1.398 23.934 12.968 0 10.008-8.789 15.665-23.934 15.665-15.75 0-21.757-4.004-21.757-10.88 0-3.917 1.742-6 4.789-8.878-2.875-1.211-3.828-3.387-3.828-5.739 0-1.914.953-3.656 2.523-5.312 1.566-1.652 3.305-3.305 5.395-5.219-4.262-2.09-7.485-6.617-7.485-13.058 0-10.008 6.613-16.88 19.93-16.88 3.742 0 6.004.344 8.008.872h16.972v7.394l-8.007.61" />
<path
style="stroke: none; fill-rule: nonzero; fill-opacity: 1"
d="M130.871 31.836c-4.785 0-8.351 2.352-8.351 8.008 0 4.261 2.347 7.222 8.093 7.222 4.871 0 8.18-2.867 8.18-7.398 0-5.133-2.961-7.832-7.922-7.832Zm-9.57 39.95c-1.133 1.39-2.262 2.87-2.262 4.612 0 3.48 4.434 4.524 10.527 4.524 5.051 0 11.926-.352 11.926-5.043 0-2.793-3.308-2.965-7.488-3.227Zm25.761-39.688c1.563 2.004 3.22 4.789 3.22 8.793 0 9.656-7.571 15.316-18.536 15.316-2.789 0-5.312-.348-6.879-.785l-2.87 4.613 8.526.52c15.059.96 23.934 1.398 23.934 12.968 0 10.008-8.789 15.665-23.934 15.665-15.75 0-21.757-4.004-21.757-10.88 0-3.917 1.742-6 4.789-8.878-2.875-1.211-3.828-3.387-3.828-5.739 0-1.914.953-3.656 2.523-5.312 1.566-1.652 3.305-3.305 5.395-5.219-4.262-2.09-7.485-6.617-7.485-13.058 0-10.008 6.613-16.88 19.93-16.88 3.742 0 6.004.344 8.008.872h16.972v7.394l-8.007.61"
/>
<g clip-path="url(#a)">
<path style="stroke: none; fill-rule: nonzero; fill-opacity: 1" d="M170.379 16.281c-4.961 0-7.832-2.87-7.832-7.836 0-4.957 2.871-7.656 7.832-7.656 5.05 0 7.922 2.7 7.922 7.656 0 4.965-2.871 7.836-7.922 7.836Zm-11.227 52.305V61.71l4.438-.606c1.219-.175 1.394-.437 1.394-1.746V33.773c0-.953-.261-1.566-1.132-1.824l-4.7-1.656.957-7.047h18.016V59.36c0 1.399.086 1.57 1.395 1.746l4.437.606v6.875h-24.805" />
<path
style="stroke: none; fill-rule: nonzero; fill-opacity: 1"
d="M170.379 16.281c-4.961 0-7.832-2.87-7.832-7.836 0-4.957 2.871-7.656 7.832-7.656 5.05 0 7.922 2.7 7.922 7.656 0 4.965-2.871 7.836-7.922 7.836Zm-11.227 52.305V61.71l4.438-.606c1.219-.175 1.394-.437 1.394-1.746V33.773c0-.953-.261-1.566-1.132-1.824l-4.7-1.656.957-7.047h18.016V59.36c0 1.399.086 1.57 1.395 1.746l4.437.606v6.875h-24.805"
/>
</g>
<g clip-path="url(#b)">
<path style="stroke: none; fill-rule: nonzero; fill-opacity: 1" d="M218.371 65.21c-3.742 1.825-9.223 3.481-14.187 3.481-10.356 0-14.27-4.175-14.27-14.015V31.879c0-.524 0-.871-.7-.871h-6.093v-7.746c7.664-.871 10.707-4.703 11.664-14.188h8.27v12.36c0 .609 0 .87.695.87h12.27v8.704h-12.965v20.797c0 5.136 1.218 7.136 5.918 7.136 2.437 0 4.96-.609 7.047-1.39l2.351 7.66" />
<path
style="stroke: none; fill-rule: nonzero; fill-opacity: 1"
d="M218.371 65.21c-3.742 1.825-9.223 3.481-14.187 3.481-10.356 0-14.27-4.175-14.27-14.015V31.879c0-.524 0-.871-.7-.871h-6.093v-7.746c7.664-.871 10.707-4.703 11.664-14.188h8.27v12.36c0 .609 0 .87.695.87h12.27v8.704h-12.965v20.797c0 5.136 1.218 7.136 5.918 7.136 2.437 0 4.96-.609 7.047-1.39l2.351 7.66"
/>
</g>
<g clip-path="url(#c)">
<path style="stroke: none; fill-rule: nonzero; fill-opacity: 1" d="M89.422 42.371 49.629 2.582a5.868 5.868 0 0 0-8.3 0l-8.263 8.262 10.48 10.484a6.965 6.965 0 0 1 7.173 1.668 6.98 6.98 0 0 1 1.656 7.215l10.102 10.105a6.963 6.963 0 0 1 7.214 1.657 6.976 6.976 0 0 1 0 9.875 6.98 6.98 0 0 1-9.879 0 6.987 6.987 0 0 1-1.519-7.594l-9.422-9.422v24.793a6.979 6.979 0 0 1 1.848 1.32 6.988 6.988 0 0 1 0 9.88c-2.73 2.726-7.153 2.726-9.875 0a6.98 6.98 0 0 1 0-9.88 6.893 6.893 0 0 1 2.285-1.523V34.398a6.893 6.893 0 0 1-2.285-1.523 6.988 6.988 0 0 1-1.508-7.637L29.004 14.902 1.719 42.187a5.868 5.868 0 0 0 0 8.301l39.793 39.793a5.868 5.868 0 0 0 8.3 0l39.61-39.605a5.873 5.873 0 0 0 0-8.305" />
<path
style="stroke: none; fill-rule: nonzero; fill-opacity: 1"
d="M89.422 42.371 49.629 2.582a5.868 5.868 0 0 0-8.3 0l-8.263 8.262 10.48 10.484a6.965 6.965 0 0 1 7.173 1.668 6.98 6.98 0 0 1 1.656 7.215l10.102 10.105a6.963 6.963 0 0 1 7.214 1.657 6.976 6.976 0 0 1 0 9.875 6.98 6.98 0 0 1-9.879 0 6.987 6.987 0 0 1-1.519-7.594l-9.422-9.422v24.793a6.979 6.979 0 0 1 1.848 1.32 6.988 6.988 0 0 1 0 9.88c-2.73 2.726-7.153 2.726-9.875 0a6.98 6.98 0 0 1 0-9.88 6.893 6.893 0 0 1 2.285-1.523V34.398a6.893 6.893 0 0 1-2.285-1.523 6.988 6.988 0 0 1-1.508-7.637L29.004 14.902 1.719 42.187a5.868 5.868 0 0 0 0 8.301l39.793 39.793a5.868 5.868 0 0 0 8.3 0l39.61-39.605a5.873 5.873 0 0 0 0-8.305"
/>
</g>
</svg>
<span class="text-xs">{{ .Config.Version }}</span>
</a>
</div>
</div>
<h1 class="text-xl font-bold dark:text-white px-6 lg:ml-44">{{ block "header" . }}{{ end }}</h1>
<h1 class="text-xl font-bold dark:text-white px-6 lg:ml-44">
{{ block "header" . }}{{ end }}
</h1>
<div class="relative flex items-center justify-end w-full p-4 space-x-4">
<a href="#" class="relative block text-gray-800 dark:text-gray-200">{{ template "svg/user" (dict "Size" 20) }}</a>
<a href="#" class="relative block text-gray-800 dark:text-gray-200"
>{{ template "svg/user" (dict "Size" 20) }}</a
>
<input type="checkbox" id="user-dropdown-button" class="hidden" />
<div id="user-dropdown"
class="transition duration-200 z-20 absolute right-4 top-16 pt-4">
<div class="w-40 origin-top-right bg-white rounded-md shadow-lg dark:shadow-gray-800 dark:bg-gray-700 ring-1 ring-black ring-opacity-5">
<div class="py-1"
<div
id="user-dropdown"
class="transition duration-200 z-20 absolute right-4 top-16 pt-4"
>
<div
class="w-40 origin-top-right bg-white rounded-md shadow-lg dark:shadow-gray-800 dark:bg-gray-700 ring-1 ring-black ring-opacity-5"
>
<div
class="py-1"
role="menu"
aria-orientation="vertical"
aria-labelledby="options-menu">
<a href="/settings"
aria-labelledby="options-menu"
>
<a
href="/settings"
class="block px-4 py-2 text-md text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600"
role="menuitem">
role="menuitem"
>
<span class="flex flex-col">
<span>Settings</span>
</span>
</a>
<a href="/local"
<a
href="/local"
class="block px-4 py-2 text-md text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600"
role="menuitem">
role="menuitem"
>
<span class="flex flex-col">
<span>Offline</span>
</span>
</a>
<a href="/logout"
<a
href="/logout"
class="block px-4 py-2 text-md text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600"
role="menuitem">
role="menuitem"
>
<span class="flex flex-col">
<span>Logout</span>
</span>
@ -283,15 +398,32 @@
</div>
</div>
<label for="user-dropdown-button">
<div class="flex items-center gap-2 text-gray-500 dark:text-white text-md py-4 cursor-pointer">
<div
class="flex items-center gap-2 text-gray-500 dark:text-white text-md py-4 cursor-pointer"
>
<span>{{ .Authorization.UserName }}</span>
<span class="text-gray-800 dark:text-gray-200">{{ template "svg/dropdown" (dict "Size" 20) }}</span>
<span class="text-gray-800 dark:text-gray-200"
>{{ template "svg/dropdown" (dict "Size" 20) }}</span
>
</div>
</label>
</div>
</div>
<main class="relative overflow-hidden">
<div id="container" class="h-[100dvh] px-4 overflow-auto md:px-6 lg:ml-48">{{ block "content" . }}{{ end }}</div>
<div
id="container"
class="h-[100dvh] px-4 overflow-auto md:px-6 lg:ml-48"
>
{{ block "content" . }}{{ end }}
</div>
</main>
<div class="absolute right-4 bottom-4">
{{ block "notifications" . }}{{ end }}
<!--
<div class="w-72 p-4 bg-red-500 rounded-xl">
<span>User Deleted</span>
</div>
-->
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
{{ template "base" . }}
{{ define "title" }}Activity{{ end }}
{{ define "header" }}<a href="./activity">Activity</a>{{ end }}
{{ define "content" }}
<div class="overflow-x-auto">
<div class="inline-block min-w-full overflow-hidden rounded shadow">
<!-- Table Component - Utilizes Template "table-cell" -->
{{ template "component/table" (dict
"Columns" (slice "Document" "Time" "Duration" "Percent")
"Keys" (slice "Document" "StartTime" "Duration" "EndPercentage")
"Rows" .Data
)
}}
</div>
</div>
{{ end }}
<!-- Table Cell Definition -->
{{ define "table-cell" }}
{{ if eq .Name "Document" }}
<a href="./documents/{{ .Data.DocumentID }}"
>{{ .Data.Author }} - {{ .Data.Title }}</a
>
{{ else if eq .Name "EndPercentage" }}
{{ index (fields .Data) .Name }}%
{{ else }}
{{ index (fields .Data) .Name }}
{{ end }}
{{ end }}

View File

@ -7,8 +7,15 @@
{{ end }}
<!-- Type -->
{{ if eq .Type "Link" }}
<a href="{{ .URL }}" class="text-center {{ $baseClass }}" type="submit">{{ .Title }}</a>
<a href="{{ .URL }}" class="text-center {{ $baseClass }}" type="submit"
>{{ .Title }}</a
>
{{ else }}
<button class="{{ $baseClass }}" type="submit" {{ if .FormName }} form="{{ .FormName}}" {{ end }}>{{ .Title }}
<button
class="{{ $baseClass }}"
type="submit"
{{ if .FormName }}form="{{ .FormName }}"{{ end }}
>
{{ .Title }}
</button>
{{ end }}

View File

@ -1,8 +1,13 @@
<div class="w-full relative">
<div class="flex gap-4 w-full h-full p-4 shadow-lg bg-white dark:bg-gray-700 rounded">
<div
class="flex gap-4 w-full h-full p-4 shadow-lg bg-white dark:bg-gray-700 rounded"
>
<div class="min-w-fit my-auto h-48 relative">
<a href="./documents/{{ .ID }}">
<img class="rounded object-cover h-full" src="./documents/{{.ID}}/cover" />
<img
class="rounded object-cover h-full"
src="./documents/{{ .ID }}/cover"
/>
</a>
</div>
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
@ -31,7 +36,9 @@
</div>
</div>
</div>
<div class="absolute flex flex-col gap-2 right-4 bottom-4 text-gray-500 dark:text-gray-400">
<div
class="absolute flex flex-col gap-2 right-4 bottom-4 text-gray-500 dark:text-gray-400"
>
<a href="./activity?document={{ .ID }}">{{ template "svg/activity" }}</a>
{{ if .Filepath }}
<a href="./documents/{{ .ID }}/file">{{ template "svg/download" }}</a>

View File

@ -1,5 +1,13 @@
<div class="absolute -translate-y-1/2 p-4 m-auto bg-gray-700 dark:bg-gray-300 rounded-lg shadow w-full text-black dark:text-white">
<span class="inline-flex gap-2 items-center font-medium text-xs inline-block py-1 px-2 uppercase rounded-full {{ if .Error }} bg-red-500 {{ else if true }} bg-green-600 {{ end }}">
<div
class="absolute -translate-y-1/2 p-4 m-auto bg-gray-700 dark:bg-gray-300 rounded-lg shadow w-full text-black dark:text-white"
>
<span
class="inline-flex gap-2 items-center font-medium text-xs inline-block py-1 px-2 uppercase rounded-full {{ if .Error }}
bg-red-500
{{ else if true }}
bg-green-600
{{ end }}"
>
{{ if and (ne .Progress 100) (not .Error) }}
{{ template "svg/loading" (dict "Size" 16) }}
{{ end }}
@ -8,15 +16,27 @@
<div class="flex flex-col gap-2 mt-2">
<div class="relative w-full h-4 bg-gray-300 dark:bg-gray-700 rounded-full">
{{ if .Error }}
<div class="absolute h-full bg-red-500 rounded-full" style="width: 100%"></div>
<p class="absolute w-full h-full font-bold text-center text-xs">ERROR</p>
<div
class="absolute h-full bg-red-500 rounded-full"
style="width: 100%"
></div>
<p class="absolute w-full h-full font-bold text-center text-xs">
ERROR
</p>
{{ else }}
<div class="absolute h-full bg-green-600 rounded-full"
style="width: {{ .Progress }}%"></div>
<p class="absolute w-full h-full font-bold text-center text-xs">{{ .Progress }}%</p>
<div
class="absolute h-full bg-green-600 rounded-full"
style="width: {{ .Progress }}%"
></div>
<p class="absolute w-full h-full font-bold text-center text-xs">
{{ .Progress }}%
</p>
{{ end }}
</div>
<a href="{{ .ButtonHref }}"
class="w-full text-center font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100">{{ .ButtonText }}</a>
<a
href="{{ .ButtonHref }}"
class="w-full text-center font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
>{{ .ButtonText }}</a
>
</div>
</div>

View File

@ -4,14 +4,26 @@
<label class="my-auto cursor-pointer" for="edit-{{ .FormValue }}-button">
{{ template "svg/edit" (dict "Size" 18) }}
</label>
<input type="checkbox"
<input
type="checkbox"
id="edit-{{ .FormValue }}-button"
class="hidden css-button" />
<div class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
<form method="POST"
class="hidden css-button"
/>
<div
class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600"
>
<form
method="POST"
action="{{ .URL }}"
class="flex flex-col gap-2 text-black dark:text-white text-sm">
<input type="text" id="{{ .FormValue }}" name="{{ .FormValue }}" value="{{ or .Value "N/A" }}" class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white" />
class="flex flex-col gap-2 text-black dark:text-white text-sm"
>
<input
type="text"
id="{{ .FormValue }}"
name="{{ .FormValue }}"
value="{{ or .Value "N/A" }}"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
/>
{{ template "component/button" (dict "Title" "Save") }}
</form>
</div>

View File

@ -1,62 +1,87 @@
{{ if .Error }}
<div class="absolute top-0 left-0 w-full h-full z-50">
<div class="fixed top-0 left-0 bg-black opacity-50 w-screen h-screen"></div>
<div class="relative flex flex-col gap-4 p-4 max-h-[95%] bg-white dark:bg-gray-800 overflow-scroll -translate-x-2/4 -translate-y-2/4 top-1/2 left-1/2 w-5/6 overflow-hidden shadow rounded">
<div
class="relative flex flex-col gap-4 p-4 max-h-[95%] bg-white dark:bg-gray-800 overflow-scroll -translate-x-2/4 -translate-y-2/4 top-1/2 left-1/2 w-5/6 overflow-hidden shadow rounded"
>
<div class="text-center">
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">No Metadata Results Found</h3>
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">
No Metadata Results Found
</h3>
</div>
{{ template "component/button" (dict
"Title" "Back to Document"
"Type" "Link"
"URL" (printf "/documents/%s" .ID)
)}}
)
}}
</div>
</div>
{{ end }}
{{ if .Metadata }}
<div class="absolute top-0 left-0 w-full h-full z-50">
<div class="fixed top-0 left-0 bg-black opacity-50 w-screen h-screen"></div>
<div class="relative max-h-[95%] bg-white dark:bg-gray-800 overflow-scroll -translate-x-2/4 -translate-y-2/4 top-1/2 left-1/2 w-5/6 overflow-hidden shadow rounded">
<div
class="relative max-h-[95%] bg-white dark:bg-gray-800 overflow-scroll -translate-x-2/4 -translate-y-2/4 top-1/2 left-1/2 w-5/6 overflow-hidden shadow rounded"
>
<div class="py-5 text-center">
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">Metadata Results</h3>
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">
Metadata Results
</h3>
</div>
<form id="metadata-save"
<form
id="metadata-save"
method="POST"
action="/documents/{{ .ID }}/edit"
class="text-black dark:text-white border-b dark:border-black">
class="text-black dark:text-white border-b dark:border-black"
>
<dl>
<div class="p-3 bg-gray-100 dark:bg-gray-900 grid grid-cols-3 gap-4 sm:px-6">
<div
class="p-3 bg-gray-100 dark:bg-gray-900 grid grid-cols-3 gap-4 sm:px-6"
>
<dt class="my-auto font-medium text-gray-500">Cover</dt>
<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2">
<img class="rounded object-fill h-32"
src="https://books.google.com/books/content/images/frontcover/{{ .Metadata.ID }}?fife=w480-h690" />
<img
class="rounded object-fill h-32"
src="https://books.google.com/books/content/images/frontcover/{{ .Metadata.ID }}?fife=w480-h690"
/>
</dd>
</div>
<div class="p-3 bg-white dark:bg-gray-800 grid grid-cols-3 gap-4 sm:px-6">
<div
class="p-3 bg-white dark:bg-gray-800 grid grid-cols-3 gap-4 sm:px-6"
>
<dt class="my-auto font-medium text-gray-500">Title</dt>
<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2">
{{ or .Metadata.Title "N/A" }}
</dd>
</div>
<div class="p-3 bg-gray-100 dark:bg-gray-900 grid grid-cols-3 gap-4 sm:px-6">
<div
class="p-3 bg-gray-100 dark:bg-gray-900 grid grid-cols-3 gap-4 sm:px-6"
>
<dt class="my-auto font-medium text-gray-500">Author</dt>
<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2">
{{ or .Metadata.Author "N/A" }}
</dd>
</div>
<div class="p-3 bg-white dark:bg-gray-800 grid grid-cols-3 gap-4 sm:px-6">
<div
class="p-3 bg-white dark:bg-gray-800 grid grid-cols-3 gap-4 sm:px-6"
>
<dt class="my-auto font-medium text-gray-500">ISBN 10</dt>
<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2">
{{ or .Metadata.ISBN10 "N/A" }}
</dd>
</div>
<div class="p-3 bg-gray-100 dark:bg-gray-900 grid grid-cols-3 gap-4 sm:px-6">
<div
class="p-3 bg-gray-100 dark:bg-gray-900 grid grid-cols-3 gap-4 sm:px-6"
>
<dt class="my-auto font-medium text-gray-500">ISBN 13</dt>
<dd class="mt-1 text-sm sm:mt-0 sm:col-span-2">
{{ or .Metadata.ISBN13 "N/A" }}
</dd>
</div>
<div class="p-3 bg-white dark:bg-gray-800 sm:grid sm:grid-cols-3 sm:gap-4 px-6">
<div
class="p-3 bg-white dark:bg-gray-800 sm:grid sm:grid-cols-3 sm:gap-4 px-6"
>
<dt class="my-auto font-medium text-gray-500">Description</dt>
<dd class="max-h-[10em] overflow-scroll mt-1 sm:mt-0 sm:col-span-2">
{{ or .Metadata.Description "N/A" }}
@ -64,24 +89,42 @@
</div>
</dl>
<div class="hidden">
<input type="text" id="title" name="title" value="{{ .Metadata.Title }}" />
<input type="text" id="author" name="author" value="{{ .Metadata.Author }}" />
<input type="text"
<input
type="text"
id="title"
name="title"
value="{{ .Metadata.Title }}"
/>
<input
type="text"
id="author"
name="author"
value="{{ .Metadata.Author }}"
/>
<input
type="text"
id="description"
name="description"
value="{{ .Metadata.Description }}" />
<input type="text"
value="{{ .Metadata.Description }}"
/>
<input
type="text"
id="isbn_10"
name="isbn_10"
value="{{ .Metadata.ISBN10 }}" />
<input type="text"
value="{{ .Metadata.ISBN10 }}"
/>
<input
type="text"
id="isbn_13"
name="isbn_13"
value="{{ .Metadata.ISBN13 }}" />
<input type="text"
value="{{ .Metadata.ISBN13 }}"
/>
<input
type="text"
id="cover_gbid"
name="cover_gbid"
value="{{ .Metadata.ID }}" />
value="{{ .Metadata.ID }}"
/>
</div>
</form>
<div class="flex justify-end">
@ -90,11 +133,13 @@
"Title" "Cancel"
"Type" "Link"
"URL" (printf "/documents/%s" .ID)
)}}
)
}}
{{ template "component/button" (dict
"Title" "Save"
"FormName" "metadata-save"
)}}
)
}}
</div>
</div>
</div>

View File

@ -1,6 +1,10 @@
<div class="w-full">
<div class="relative w-full px-4 py-6 bg-white shadow-lg dark:bg-gray-700 rounded">
<p class="text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500">
<div
class="relative w-full px-4 py-6 bg-white shadow-lg dark:bg-gray-700 rounded"
>
<p
class="text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500"
>
{{ if eq .Window "WEEK" }}
Weekly Read Streak
{{ else }}
@ -8,16 +12,25 @@
{{ end }}
</p>
<div class="flex items-end my-6 space-x-2">
<p class="text-5xl font-bold text-black dark:text-white">{{ .CurrentStreak }}</p>
<p class="text-5xl font-bold text-black dark:text-white">
{{ .CurrentStreak }}
</p>
</div>
<div class="dark:text-white">
<div class="flex items-center justify-between pb-2 mb-2 text-sm border-b border-gray-200">
<div
class="flex items-center justify-between pb-2 mb-2 text-sm border-b border-gray-200"
>
<div>
<p>
{{ if eq .Window "WEEK" }} Current Weekly Streak {{ else }}
Current Daily Streak {{ end }}
{{ if eq .Window "WEEK" }}
Current Weekly Streak
{{ else }}
Current Daily Streak
{{ end }}
</p>
<div class="flex items-end text-sm text-gray-400">{{ .CurrentStreakStartDate }} ➞ {{ .CurrentStreakEndDate }}</div>
<div class="flex items-end text-sm text-gray-400">
{{ .CurrentStreakStartDate }} ➞ {{ .CurrentStreakEndDate }}
</div>
</div>
<div class="flex items-end font-bold">{{ .CurrentStreak }}</div>
</div>
@ -30,7 +43,9 @@
Best Daily Streak
{{ end }}
</p>
<div class="flex items-end text-sm text-gray-400">{{ .MaxStreakStartDate }} ➞ {{ .MaxStreakEndDate }}</div>
<div class="flex items-end text-sm text-gray-400">
{{ .MaxStreakStartDate }} ➞ {{ .MaxStreakEndDate }}
</div>
</div>
<div class="flex items-end font-bold">{{ .MaxStreak }}</div>
</div>

View File

@ -5,7 +5,11 @@
<thead class="text-gray-800 dark:text-gray-400">
<tr>
{{ range $col := $cols }}
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">{{ $col }}</th>
<th
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
{{ $col }}
</th>
{{ end }}
</tr>
</thead>
@ -19,7 +23,7 @@
<tr>
{{ range $key := $keys }}
<td class="p-3 border-b border-gray-200">
<p>{{ index (fields $row) $key }}</p>
{{ template "table-cell" (dict "Data" $row "Name" $key ) }}
</td>
{{ end }}
</tr>

View File

@ -4,41 +4,25 @@
{{ define "content" }}
<div class="overflow-x-auto">
<div class="inline-block min-w-full overflow-hidden rounded shadow">
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
<thead class="text-gray-800 dark:text-gray-400">
<tr>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Time</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Duration</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Percent</th>
</tr>
</thead>
<tbody class="text-black dark:text-white">
{{ if not .Data }}
<tr>
<td class="text-center p-3" colspan="4">No Results</td>
</tr>
{{ end }}
{{ range $activity := .Data }}
<tr>
<td class="p-3 border-b border-gray-200">
<a href="./documents/{{ $activity.DocumentID }}">{{ $activity.Author }} - {{ $activity.Title }}
</p>
</a>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ $activity.StartTime }}</p>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ $activity.Duration }}</p>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ $activity.EndPercentage }}%</p>
</td>
</tr>
{{ end }}
</tbody>
</table>
<!-- Table Component - Utilizes Template "table-cell" -->
{{ template "component/table" (dict
"Columns" (slice "Document" "Time" "Duration" "Percent")
"Keys" (slice "Document" "StartTime" "Duration" "EndPercentage")
"Rows" .Data
)
}}
</div>
</div>
{{ end }}
<!-- Table Cell Definition -->
{{ define "table-cell" }}
{{ if eq .Name "Document" }}
<a href="./documents/{{ .Data.DocumentID }}"
>{{ .Data.Author }} - {{ .Data.Title }}</a
>
{{ else if eq .Name "EndPercentage" }}
{{ index (fields .Data) .Name }}%
{{ else }}
{{ index (fields .Data) .Name }}
{{ end }}
{{ end }}

View File

@ -1,15 +1,31 @@
{{ template "base" . }}
{{ define "title" }}Admin - Import Results{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Import Results</a>{{ end }}
{{ define "header" }}
<a class="whitespace-pre" href="../admin">Admin - Import Results</a>
{{ end }}
{{ define "content" }}
<div class="overflow-x-auto">
<div class="inline-block min-w-full overflow-hidden rounded shadow">
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
<table
class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm"
>
<thead class="text-gray-800 dark:text-gray-400">
<tr>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Status</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Error</th>
<th
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Document
</th>
<th
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Status
</th>
<th
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Error
</th>
</tr>
</thead>
<tbody class="text-black dark:text-white">
@ -20,8 +36,10 @@
{{ end }}
{{ range $result := .Data }}
<tr>
<td class="p-3 border-b border-gray-200 grid"
style="grid-template-columns: 4rem auto">
<td
class="p-3 border-b border-gray-200 grid"
style="grid-template-columns: 4rem auto"
>
<span class="text-gray-800 dark:text-gray-400">Name:</span>
{{ if (eq $result.ID "") }}
<span>N/A</span>

View File

@ -1,25 +1,41 @@
{{ template "base" . }}
{{ define "title" }}Admin - Import{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Import</a>{{ end }}
{{ define "header" }}
<a class="whitespace-pre" href="../admin">Admin - Import</a>
{{ end }}
{{ define "content" }}
<div class="overflow-x-auto">
<div class="inline-block min-w-full overflow-hidden rounded shadow">
{{ if .SelectedDirectory }}
<div class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<p class="text-lg font-semibold text-gray-500">Selected Import Directory</p>
<div
class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<p class="text-lg font-semibold text-gray-500">
Selected Import Directory
</p>
<form class="flex gap-4 flex-col" action="./import" method="POST">
<input type="text"
<input
type="text"
name="directory"
value="{{ .SelectedDirectory }}"
class="hidden" />
class="hidden"
/>
<div class="flex justify-between gap-4 w-full">
<div class="flex gap-4 items-center">
<span>{{ template "svg/import" }}</span>
<p class="font-medium text-lg break-all">{{ .SelectedDirectory }}</p>
<p class="font-medium text-lg break-all">
{{ .SelectedDirectory }}
</p>
</div>
<div class="flex flex-col justify-around gap-2 mr-4">
<div class="inline-flex gap-2 items-center">
<input checked type="radio" id="direct" name="type" value="DIRECT" />
<input
checked
type="radio"
id="direct"
name="type"
value="DIRECT"
/>
<label for="direct">Direct</label>
</div>
<div class="inline-flex gap-2 items-center">
@ -28,25 +44,37 @@
</div>
</div>
</div>
<button type="submit"
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
<button
type="submit"
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
>
<span class="w-full">Import Directory</span>
</button>
</form>
</div>
{{ end }}
{{ if not .SelectedDirectory }}
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
<table
class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm"
>
<thead class="text-gray-800 dark:text-gray-400">
<tr>
<th class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 w-12"></th>
<th class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 break-all">{{ .CurrentPath }}</th>
<th
class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 w-12"
></th>
<th
class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 break-all"
>
{{ .CurrentPath }}
</th>
</tr>
</thead>
<tbody class="text-black dark:text-white">
{{ if not (eq .CurrentPath "/") }}
<tr>
<td class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400"></td>
<td
class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400"
></td>
<td class="p-3 border-b border-gray-200">
<a href="./import?directory={{ $.CurrentPath }}/../">
<p>../</p>
@ -61,8 +89,12 @@
{{ end }}
{{ range $item := .Data }}
<tr>
<td class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400">
<a href="./import?select={{ $.CurrentPath }}/{{ $item }}">{{ template "svg/import" }}</a>
<td
class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400"
>
<a href="./import?select={{ $.CurrentPath }}/{{ $item }}"
>{{ template "svg/import" }}</a
>
</td>
<td class="p-3 border-b border-gray-200">
<a href="./import?directory={{ $.CurrentPath }}/{{ $item }}">

View File

@ -1,34 +1,45 @@
{{ template "base" . }}
{{ define "title" }}Admin - Logs{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Logs</a>{{ end }}
{{ define "header" }}
<a class="whitespace-pre" href="../admin">Admin - Logs</a>
{{ end }}
{{ define "content" }}
<div class="flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<form class="flex gap-4 flex-col lg:flex-row" action="./logs" method="GET">
<div class="flex flex-col w-full grow">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/search2" (dict "Size" 15) }}
</span>
<input type="text"
<input
type="text"
id="filter"
name="filter"
value="{{ .Filter }}"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-2 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="JQ Filter" />
placeholder="JQ Filter"
/>
</div>
</div>
<div class="lg:w-60">
{{ template "component/button" (dict
"Title" "Filter"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
</div>
<!-- Required for iOS "Hover" Events (onclick) -->
<div onclick
<div
onclick
class="flex flex-col-reverse text-black dark:text-white w-full overflow-scroll"
style="font-family: monospace">
style="font-family: monospace"
>
{{ range $log := .Data }}
<span class="whitespace-nowrap hover:whitespace-pre">{{ $log }}</span>
{{ end }}

View File

@ -1,23 +1,34 @@
{{ template "base" . }}
{{ define "title" }}Admin - General{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="./admin">Admin - General</a>{{ end }}
{{ define "header" }}
<a class="whitespace-pre" href="./admin">Admin - General</a>
{{ end }}
{{ define "content" }}
<div class="w-full flex flex-col gap-4 grow">
<div class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<p class="text-lg font-semibold mb-2">Backup & Restore</p>
<div class="flex flex-col gap-4">
<form class="flex justify-between" action="./admin" method="POST">
<input type="text" name="action" value="BACKUP" class="hidden" />
<div class="flex gap-8 items-center">
<div>
<input type="checkbox" id="backup_covers" name="backup_types" value="COVERS" />
<input
type="checkbox"
id="backup_covers"
name="backup_types"
value="COVERS"
/>
<label for="backup_covers">Covers</label>
</div>
<div>
<input type="checkbox"
<input
type="checkbox"
id="backup_documents"
name="backup_types"
value="DOCUMENTS" />
value="DOCUMENTS"
/>
<label for="backup_documents">Documents</label>
</div>
</div>
@ -25,22 +36,31 @@
{{ template "component/button" (dict
"Title" "Backup"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
<form method="POST"
<form
method="POST"
enctype="multipart/form-data"
action="./admin"
class="flex justify-between grow">
class="flex justify-between grow"
>
<input type="text" name="action" value="RESTORE" class="hidden" />
<div class="flex items-center w-1/2">
<input type="file" accept=".zip" name="restore_file" class="w-full" />
<input
type="file"
accept=".zip"
name="restore_file"
class="w-full"
/>
</div>
<div class="w-40 h-10">
{{ template "component/button" (dict
"Title" "Restore"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
</div>
@ -50,7 +70,9 @@
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
{{ end }}
</div>
<div class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<p class="text-lg font-semibold">Tasks</p>
<table class="min-w-full bg-white dark:bg-gray-700 text-sm">
<tbody class="text-black dark:text-white">
@ -60,12 +82,18 @@
</td>
<td class="py-2 float-right">
<form action="./admin" method="POST">
<input type="text" name="action" value="METADATA_MATCH" class="hidden" />
<input
type="text"
name="action"
value="METADATA_MATCH"
class="hidden"
/>
<div class="w-40 h-10 text-base">
{{ template "component/button" (dict
"Title" "Run"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
</td>
@ -76,12 +104,18 @@
</td>
<td class="py-2 float-right">
<form action="./admin" method="POST">
<input type="text" name="action" value="CACHE_TABLES" class="hidden" />
<input
type="text"
name="action"
value="CACHE_TABLES"
class="hidden"
/>
<div class="w-40 h-10 text-base">
{{ template "component/button" (dict
"Title" "Run"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
</td>

View File

@ -4,15 +4,24 @@
{{ define "content" }}
<div class="h-full w-full relative">
<!-- Document Info -->
<div class="h-full w-full overflow-scroll bg-white shadow-lg dark:bg-gray-700 rounded dark:text-white p-4">
<div class="flex flex-col gap-2 float-left w-44 md:w-60 lg:w-80 mr-4 mb-2 relative">
<div
class="h-full w-full overflow-scroll bg-white shadow-lg dark:bg-gray-700 rounded dark:text-white p-4"
>
<div
class="flex flex-col gap-2 float-left w-44 md:w-60 lg:w-80 mr-4 mb-2 relative"
>
<label class="z-10 cursor-pointer" for="edit-cover-button">
<img class="rounded object-fill w-full"
src="/documents/{{.Data.ID}}/cover" />
<img
class="rounded object-fill w-full"
src="/documents/{{ .Data.ID }}/cover"
/>
</label>
{{ if .Data.Filepath }}
<a href="/reader#id={{ .Data.ID }}&type=REMOTE"
class="z-10 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded text-sm text-center py-1 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Read</a>
<a
href="/reader#id={{ .Data.ID }}&type=REMOTE"
class="z-10 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded text-sm text-center py-1 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800"
>Read</a
>
{{ end }}
<div class="flex flex-wrap-reverse justify-between z-20 gap-2 relative">
<div class="min-w-[50%] md:mr-2">
@ -25,70 +34,114 @@
<p class="font-medium">{{ or .Data.Isbn13 "N/A" }}</p>
</div>
</div>
<div class="flex grow justify-between my-auto text-gray-500 dark:text-gray-500">
<input type="checkbox" id="edit-cover-button" class="hidden css-button" />
<div class="absolute z-30 flex flex-col gap-2 top-0 left-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
<form method="POST"
<div
class="flex grow justify-between my-auto text-gray-500 dark:text-gray-500"
>
<input
type="checkbox"
id="edit-cover-button"
class="hidden css-button"
/>
<div
class="absolute z-30 flex flex-col gap-2 top-0 left-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600"
>
<form
method="POST"
enctype="multipart/form-data"
action="./{{ .Data.ID }}/edit"
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm">
<input type="file" id="cover_file" name="cover_file">
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm"
>
<input type="file" id="cover_file" name="cover_file" />
{{ template "component/button" (dict "Title" "Upload Cover") }}
</form>
<form method="POST"
<form
method="POST"
action="./{{ .Data.ID }}/edit"
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm">
<input type="checkbox"
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm"
>
<input
type="checkbox"
checked
id="remove_cover"
name="remove_cover"
class="hidden" />
class="hidden"
/>
{{ template "component/button" (dict "Title" "Remove Cover") }}
</form>
</div>
<div class="relative">
<label for="delete-button" class="cursor-pointer">{{ template "svg/delete" (dict "Size" 28) }}</label>
<input type="checkbox" id="delete-button" class="hidden css-button" />
<div class="absolute z-30 bottom-7 left-5 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
<form method="POST"
<label for="delete-button" class="cursor-pointer"
>{{ template "svg/delete" (dict "Size" 28) }}</label
>
<input
type="checkbox"
id="delete-button"
class="hidden css-button"
/>
<div
class="absolute z-30 bottom-7 left-5 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600"
>
<form
method="POST"
action="./{{ .Data.ID }}/delete"
class="text-black dark:text-white text-sm w-24">
class="text-black dark:text-white text-sm w-24"
>
{{ template "component/button" (dict "Title" "Delete") }}
</form>
</div>
</div>
<a href="../activity?document={{ .Data.ID }}">{{ template "svg/activity" (dict "Size" 28) }}</a>
<a href="../activity?document={{ .Data.ID }}"
>{{ template "svg/activity" (dict "Size" 28) }}</a
>
<div class="relative">
<label for="search-button">{{ template "svg/search" (dict "Size" 28) }}</label>
<input type="checkbox" id="search-button" class="hidden css-button" />
<div class="absolute z-30 bottom-7 left-5 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
<form method="POST"
<label for="search-button"
>{{ template "svg/search" (dict "Size" 28) }}</label
>
<input
type="checkbox"
id="search-button"
class="hidden css-button"
/>
<div
class="absolute z-30 bottom-7 left-5 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600"
>
<form
method="POST"
action="./{{ .Data.ID }}/identify"
class="flex flex-col gap-2 text-black dark:text-white text-sm">
<input type="text"
class="flex flex-col gap-2 text-black dark:text-white text-sm"
>
<input
type="text"
id="title"
name="title"
placeholder="Title"
value="{{ or .Data.Title nil }}"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white">
<input type="text"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
/>
<input
type="text"
id="author"
name="author"
placeholder="Author"
value="{{ or .Data.Author nil }}"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white">
<input type="text"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
/>
<input
type="text"
id="isbn"
name="isbn"
placeholder="ISBN 10 / ISBN 13"
value="{{ or .Data.Isbn13 (or .Data.Isbn10 nil) }}"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white">
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
/>
{{ template "component/button" (dict "Title" "Identify") }}
</form>
</div>
</div>
{{ if .Data.Filepath }}
<a href="./{{.Data.ID}}/file">{{ template "svg/download" (dict "Size" 28) }}</a>
<a href="./{{ .Data.ID }}/file"
>{{ template "svg/download" (dict "Size" 28) }}</a
>
{{ else }}
{{ template "svg/download" (dict "Size" 28 "Disabled" true) }}
{{ end }}
@ -101,22 +154,34 @@
"Value" .Data.Title
"URL" (printf "./%s/edit" .Data.ID)
"FormValue" "title"
)}}
)
}}
{{ template "component/key-val-edit" (dict
"Title" "Author"
"Value" .Data.Author
"URL" (printf "./%s/edit" .Data.ID)
"FormValue" "author"
)}}
)
}}
<div class="relative">
<div class="text-gray-500 inline-flex gap-2 relative">
<p>Time Read</p>
<label class="my-auto" for="progress-info-button">{{ template "svg/info" (dict "Size" 18) }}</label>
<input type="checkbox" id="progress-info-button" class="hidden css-button" />
<div class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
<label class="my-auto" for="progress-info-button"
>{{ template "svg/info" (dict "Size" 18) }}</label
>
<input
type="checkbox"
id="progress-info-button"
class="hidden css-button"
/>
<div
class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600"
>
<div class="text-xs flex">
<p class="text-gray-400 w-32">Seconds / Percent</p>
<p class="font-medium dark:text-white">{{ .Data.SecondsPerPercent }}</p>
<p class="font-medium dark:text-white">
{{ .Data.SecondsPerPercent }}
</p>
</div>
<div class="text-xs flex">
<p class="text-gray-400 w-32">Words / Minute</p>
@ -124,11 +189,15 @@
</div>
<div class="text-xs flex">
<p class="text-gray-400 w-32">Est. Time Left</p>
<p class="font-medium dark:text-white whitespace-nowrap">{{ niceSeconds .TotalTimeLeftSeconds }}</p>
<p class="font-medium dark:text-white whitespace-nowrap">
{{ niceSeconds .TotalTimeLeftSeconds }}
</p>
</div>
</div>
</div>
<p class="font-medium text-lg">{{ niceSeconds .Data.TotalTimeSeconds }}</p>
<p class="font-medium text-lg">
{{ niceSeconds .Data.TotalTimeSeconds }}
</p>
</div>
<div>
<p class="text-gray-500">Progress</p>
@ -138,23 +207,37 @@
<div class="relative">
<div class="text-gray-500 inline-flex gap-2 relative">
<p>Description</p>
<label class="my-auto" for="edit-description-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
<label class="my-auto" for="edit-description-button"
>{{ template "svg/edit" (dict "Size" 18) }}</label
>
</div>
</div>
<div class="relative font-medium text-justify hyphens-auto">
<input type="checkbox"
<input
type="checkbox"
id="edit-description-button"
class="hidden css-button" />
<div class="absolute h-full w-full min-h-[10em] z-30 top-1 right-0 gap-4 flex transition-all duration-200">
<img class="hidden md:block invisible rounded w-44 md:w-60 lg:w-80 object-fill"
src="/documents/{{.Data.ID}}/cover" />
<form method="POST"
class="hidden css-button"
/>
<div
class="absolute h-full w-full min-h-[10em] z-30 top-1 right-0 gap-4 flex transition-all duration-200"
>
<img
class="hidden md:block invisible rounded w-44 md:w-60 lg:w-80 object-fill"
src="/documents/{{ .Data.ID }}/cover"
/>
<form
method="POST"
action="./{{ .Data.ID }}/edit"
class="flex flex-col gap-2 w-full text-black bg-gray-200 rounded shadow-lg shadow-gray-500 dark:text-white dark:shadow-gray-900 dark:bg-gray-600 text-sm p-3">
<textarea type="text"
class="flex flex-col gap-2 w-full text-black bg-gray-200 rounded shadow-lg shadow-gray-500 dark:text-white dark:shadow-gray-900 dark:bg-gray-600 text-sm p-3"
>
<textarea
type="text"
id="description"
name="description"
class="h-full w-full p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white">{{ or .Data.Description "N/A" }}</textarea>
class="h-full w-full p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
>
{{ or .Data.Description "N/A" }}</textarea
>
{{ template "component/button" (dict "Title" "Save") }}
</form>
</div>
@ -165,6 +248,7 @@
"ID" .Data.ID
"Metadata" .Metadata
"Error" .MetadataError
)}}
)
}}
</div>
{{ end }}

View File

@ -2,27 +2,36 @@
{{ define "title" }}Documents{{ end }}
{{ define "header" }}<a href="./documents">Documents</a>{{ end }}
{{ define "content" }}
<div class="flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<form class="flex gap-4 flex-col lg:flex-row"
<div
class="flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<form
class="flex gap-4 flex-col lg:flex-row"
action="./documents"
method="GET">
method="GET"
>
<div class="flex flex-col w-full grow">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/search2" (dict "Size" 15) }}
</span>
<input type="text"
<input
type="text"
id="search"
name="search"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-2 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="Search Author / Title" />
placeholder="Search Author / Title"
/>
</div>
</div>
<div class="lg:w-60">
{{ template "component/button" (dict
"Title" "Search"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
</div>
@ -33,32 +42,58 @@
</div>
<div class="w-full flex gap-4 justify-center mt-4 text-black dark:text-white">
{{ if .PreviousPage }}
<a href="./documents?page={{ .PreviousPage }}&limit={{ .PageLimit }}"
class="bg-white shadow-lg dark:bg-gray-600 hover:bg-gray-400 font-medium rounded text-sm text-center p-2 w-24 dark:hover:bg-gray-700 focus:outline-none">◄</a>
<a
href="./documents?page={{ .PreviousPage }}&limit={{ .PageLimit }}"
class="bg-white shadow-lg dark:bg-gray-600 hover:bg-gray-400 font-medium rounded text-sm text-center p-2 w-24 dark:hover:bg-gray-700 focus:outline-none"
>◄</a
>
{{ end }}
{{ if .NextPage }}
<a href="./documents?page={{ .NextPage }}&limit={{ .PageLimit }}"
class="bg-white shadow-lg dark:bg-gray-600 hover:bg-gray-400 font-medium rounded text-sm text-center p-2 w-24 dark:hover:bg-gray-700 focus:outline-none">►</a>
<a
href="./documents?page={{ .NextPage }}&limit={{ .PageLimit }}"
class="bg-white shadow-lg dark:bg-gray-600 hover:bg-gray-400 font-medium rounded text-sm text-center p-2 w-24 dark:hover:bg-gray-700 focus:outline-none"
>►</a
>
{{ end }}
</div>
<div class="fixed bottom-6 right-6 rounded-full flex items-center justify-center">
<div
class="fixed bottom-6 right-6 rounded-full flex items-center justify-center"
>
<input type="checkbox" id="upload-file-button" class="hidden css-button" />
<div class="absolute right-0 z-10 bottom-0 rounded p-4 bg-gray-800 dark:bg-gray-200 text-white dark:text-black w-72 text-sm flex flex-col gap-2">
<form method="POST"
<div
class="absolute right-0 z-10 bottom-0 rounded p-4 bg-gray-800 dark:bg-gray-200 text-white dark:text-black w-72 text-sm flex flex-col gap-2"
>
<form
method="POST"
enctype="multipart/form-data"
action="./documents"
class="flex flex-col gap-2">
<input type="file" accept=".epub" id="document_file" name="document_file" />
<button class="font-medium px-2 py-1 text-gray-800 bg-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-800"
type="submit">Upload File</button>
class="flex flex-col gap-2"
>
<input
type="file"
accept=".epub"
id="document_file"
name="document_file"
/>
<button
class="font-medium px-2 py-1 text-gray-800 bg-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-800"
type="submit"
>
Upload File
</button>
</form>
<label for="upload-file-button">
<div class="w-full text-center cursor-pointer font-medium mt-2 px-2 py-1 text-gray-800 bg-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-800">
<div
class="w-full text-center cursor-pointer font-medium mt-2 px-2 py-1 text-gray-800 bg-gray-500 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-800"
>
Cancel Upload
</div>
</label>
</div>
<label class="w-16 h-16 bg-gray-800 dark:bg-gray-200 rounded-full flex items-center justify-center opacity-30 hover:opacity-100 transition-all duration-200 cursor-pointer"
for="upload-file-button">{{ template "svg/upload" (dict "Size" 34) }}</label>
<label
class="w-16 h-16 bg-gray-800 dark:bg-gray-200 rounded-full flex items-center justify-center opacity-30 hover:opacity-100 transition-all duration-200 cursor-pointer"
for="upload-file-button"
>{{ template "svg/upload" (dict "Size" 34) }}</label
>
</div>
{{ end }}

View File

@ -1,30 +1,53 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" />
<meta
name="viewport"
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style"
content="black-translucent" />
<meta name="theme-color"
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<meta
name="theme-color"
content="#F3F4F6"
media="(prefers-color-scheme: light)" />
<meta name="theme-color"
media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#1F2937"
media="(prefers-color-scheme: dark)" />
media="(prefers-color-scheme: dark)"
/>
<title>AnthoLume - Error</title>
<link rel="manifest" href="/manifest.json" />
<link rel="stylesheet" href="/assets/style.css" />
</head>
<body class="bg-gray-100 dark:bg-gray-800 flex flex-col justify-center h-screen">
<body
class="bg-gray-100 dark:bg-gray-800 flex flex-col justify-center h-screen"
>
<div class="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
<div class="mx-auto max-w-screen-sm text-center">
<h1 class="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-gray-600 dark:text-gray-500">{{ .Status }}</h1>
<p class="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">{{ .Error }}</p>
<p class="mb-8 text-lg font-light text-gray-500 dark:text-gray-400">{{ .Message }}</p>
<a href="/"
class="rounded text-center font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100">Back to Homepage</a>
<h1
class="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-gray-600 dark:text-gray-500"
>
{{ .Status }}
</h1>
<p
class="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white"
>
{{ .Error }}
</p>
<p class="mb-8 text-lg font-light text-gray-500 dark:text-gray-400">
{{ .Message }}
</p>
<a
href="/"
class="rounded text-center font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
>Back to Homepage</a
>
</div>
</div>
</body>

View File

@ -5,34 +5,52 @@
<div class="flex flex-col gap-4">
<div class="w-full">
<div class="relative w-full bg-white shadow-lg dark:bg-gray-700 rounded">
<p class="absolute top-3 left-5 text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500">
<p
class="absolute top-3 left-5 text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500"
>
Daily Read Totals
</p>
{{ $data := (getSVGGraphData .Data.GraphData 800 70 ) }}
<div class="relative">
<svg viewBox="26 0 755 {{ $data.Height }}"
<svg
viewBox="26 0 755 {{ $data.Height }}"
preserveAspectRatio="none"
width="100%"
height="6em">
height="6em"
>
<!-- Bezier Line Graph -->
<path fill="#316BBE" fill-opacity="0.5" stroke="none" d="{{ $data.BezierPath }} {{ $data.BezierFill }}" />
<path
fill="#316BBE"
fill-opacity="0.5"
stroke="none"
d="{{ $data.BezierPath }} {{ $data.BezierFill }}"
/>
<path fill="none" stroke="#316BBE" d="{{ $data.BezierPath }}" />
</svg>
<div class="flex absolute w-full h-full top-0"
<div
class="flex absolute w-full h-full top-0"
style="width: calc(100%*31/30);
transform: translateX(-50%);
left: 50%">
left: 50%"
>
{{ range $index, $item := $data.LinePoints }}
<!-- Required for iOS "Hover" Events (onclick) -->
<div onclick
<div
onclick
class="opacity-0 hover:opacity-100 w-full"
style="background: linear-gradient(rgba(128, 128, 128, 0.5), rgba(128, 128, 128, 0.5)) no-repeat center/2px 100%">
<div class="flex flex-col items-center p-2 rounded absolute top-3 dark:text-white text-xs pointer-events-none"
style="background: linear-gradient(rgba(128, 128, 128, 0.5), rgba(128, 128, 128, 0.5)) no-repeat center/2px 100%"
>
<div
class="flex flex-col items-center p-2 rounded absolute top-3 dark:text-white text-xs pointer-events-none"
style="transform: translateX(-50%);
background-color: rgba(128, 128, 128, 0.2);
left: 50%">
left: 50%"
>
<span>{{ (index $.Data.GraphData $index).Date }}</span>
<span>{{ (index $.Data.GraphData $index).MinutesRead }} minutes</span>
<span
>{{ (index $.Data.GraphData $index).MinutesRead }}
minutes</span
>
</div>
</div>
{{ end }}
@ -45,21 +63,25 @@
"Title" "Documents"
"Size" .Data.DatabaseInfo.DocumentsSize
"Link" "./documents"
)}}
)
}}
{{ template "component/info-card" (dict
"Title" "Activity Records"
"Size" .Data.DatabaseInfo.ActivitySize
"Link" "./activity"
)}}
)
}}
{{ template "component/info-card" (dict
"Title" "Progress Records"
"Size" .Data.DatabaseInfo.ProgressSize
"Link" "./progress"
)}}
)
}}
{{ template "component/info-card" (dict
"Title" "Devices"
"Size" .Data.DatabaseInfo.DevicesSize
)}}
)
}}
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
{{ range $item := .Data.Streaks }}
@ -70,15 +92,18 @@
{{ template "component/leaderboard-card" (dict
"Name" "WPM"
"Data" .Data.UserStatistics.WPM
)}}
)
}}
{{ template "component/leaderboard-card" (dict
"Name" "Duration"
"Data" .Data.UserStatistics.Duration
)}}
)
}}
{{ template "component/leaderboard-card" (dict
"Name" "Words"
"Data" .Data.UserStatistics.Words
)}}
)
}}
</div>
</div>
{{ end }}

View File

@ -1,19 +1,29 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" />
<meta
name="viewport"
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style"
content="black-translucent" />
<meta name="theme-color"
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<meta
name="theme-color"
content="#F3F4F6"
media="(prefers-color-scheme: light)" />
<meta name="theme-color"
media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#1F2937"
media="(prefers-color-scheme: dark)" />
<title>AnthoLume - {{ if .Register }}Register{{ else }}Login{{ end }}</title>
media="(prefers-color-scheme: dark)"
/>
<title>
AnthoLume - {{ if .Register }}Register{{ else }}Login{{ end }}
</title>
<link rel="manifest" href="./manifest.json" />
<link rel="stylesheet" href="./assets/style.css" />
<!-- Service Worker / Offline Cache Flush -->
@ -32,7 +42,8 @@
html {
height: calc(100% + env(safe-area-inset-bottom));
padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
padding: env(safe-area-inset-top) env(safe-area-inset-right) 0
env(safe-area-inset-left);
}
/* No Scrollbar - IE, Edge, Firefox */
@ -50,43 +61,60 @@
<body class="bg-gray-100 dark:bg-gray-800 dark:text-white">
<div class="flex flex-wrap w-full">
<div class="flex flex-col w-full md:w-1/2">
<div class="flex flex-col justify-center px-8 pt-8 my-auto md:justify-start md:pt-0 md:px-24 lg:px-32">
<div
class="flex flex-col justify-center px-8 pt-8 my-auto md:justify-start md:pt-0 md:px-24 lg:px-32"
>
<p class="text-3xl text-center">Welcome.</p>
<form
class="flex flex-col pt-3 md:pt-8"
{{ if
.Register}}action="./register"
{{ else }}action="./login"
.Register
}}
action="./register"
{{ else }}
action="./login"
{{ end }}
method="POST"
>
<div class="flex flex-col pt-4">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/user" (dict "Size" 15) }}
</span>
<input type="text"
<input
type="text"
id="username"
name="username"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="Username" />
placeholder="Username"
/>
</div>
</div>
<div class="flex flex-col pt-4 mb-12">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/password" (dict "Size" 15) }}
</span>
<input type="password"
<input
type="password"
id="password"
name="password"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="Password" />
<span class="absolute -bottom-5 text-red-400 text-xs">{{ .Error }}</span>
placeholder="Password"
/>
<span class="absolute -bottom-5 text-red-400 text-xs"
>{{ .Error }}</span
>
</div>
</div>
<button type="submit"
class="w-full px-4 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
<button
type="submit"
class="w-full px-4 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
>
{{ if .Register }}
<span class="w-full">Register</span>
{{ else }}
@ -95,32 +123,50 @@
</button>
</form>
<div class="pt-12 pb-12 text-center">
{{ if .Config.RegistrationEnabled }} {{ if .Register }}
{{ if .Config.RegistrationEnabled }}
{{ if .Register }}
<p>
Trying to login?
<a href="./login" class="font-semibold underline">Login here.</a>
<a href="./login" class="font-semibold underline"
>Login here.</a
>
</p>
{{ else }}
<p>
Don&#x27;t have an account?
<a href="./register" class="font-semibold underline">Register here.</a>
<a href="./register" class="font-semibold underline"
>Register here.</a
>
</p>
{{ end }} {{ end }}
{{ end }}
{{ end }}
<p class="mt-4">
<a href="./local" class="font-semibold underline">Offline / Local Mode</a>
<a href="./local" class="font-semibold underline"
>Offline / Local Mode</a
>
</p>
</div>
</div>
</div>
<div class="hidden image-fader w-1/2 shadow-2xl h-screen relative md:block">
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book1.jpg" />
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book2.jpg" />
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book3.jpg" />
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book4.jpg" />
<div
class="hidden image-fader w-1/2 shadow-2xl h-screen relative md:block"
>
<img
class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book1.jpg"
/>
<img
class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book2.jpg"
/>
<img
class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book3.jpg"
/>
<img
class="w-full h-screen object-cover ease-in-out top-0 left-0"
src="/assets/images/book4.jpg"
/>
</div>
</div>
<style>

View File

@ -4,48 +4,25 @@
{{ define "content" }}
<div class="overflow-x-auto">
<div class="inline-block min-w-full overflow-hidden rounded shadow">
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
<thead class="text-gray-800 dark:text-gray-400">
<tr>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Device</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Percent</th>
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Time</th>
</tr>
</thead>
<tbody class="text-black dark:text-white">
{{ if not .Data }}
<tr>
<td class="text-center p-3" colspan="4">No Results</td>
</tr>
{{ end }}
{{ range $progress := .Data }}
<tr>
<td class="p-3 border-b border-gray-200">
<a href="./documents/{{ $progress.DocumentID }}">{{ $progress.Author }} - {{ $progress.Title }}
</p>
</a>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ $progress.DeviceName }}</p>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ $progress.Percentage }}%</p>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ $progress.CreatedAt }}</p>
</td>
</tr>
{{ end }}
</tbody>
</table>
<!--
<!-- Table Component - Utilizes Template "table-cell" -->
{{ template "component/table" (dict
"Columns" (slice "Author" "Title" "Device Name" "Percentage" "Created At")
"Keys" (slice "Author" "Title" "DeviceName" "Percentage" "CreatedAt")
"Columns" (slice "Document" "Device Name" "Percentage" "Created At")
"Keys" (slice "Document" "DeviceName" "Percentage" "CreatedAt")
"Rows" .Data
)}}
-->
)
}}
</div>
</div>
{{ end }}
<!-- Table Cell Definition -->
{{ define "table-cell" }}
{{ if eq .Name "Document" }}
<a href="./documents/{{ .Data.DocumentID }}"
>{{ .Data.Author }} - {{ .Data.Title }}</a
>
{{ else if eq .Name "Percentage" }}
{{ index (fields .Data) .Name }}%
{{ else }}
{{ index (fields .Data) .Name }}
{{ end }}
{{ end }}

View File

@ -4,27 +4,37 @@
{{ define "content" }}
<div class="w-full flex flex-col md:flex-row gap-4">
<div class="flex flex-col gap-4 grow">
<div class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<form class="flex gap-4 flex-col lg:flex-row" action="./search">
<div class="flex flex-col w-full grow">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/search2" (dict "Size" 15) }}
</span>
<input type="text"
<input
type="text"
id="query"
name="query"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="Query" />
placeholder="Query"
/>
</div>
</div>
<div class="flex relative min-w-[12em]">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/documents" (dict "Size" 15) }}
</span>
<select class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
<select
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
id="source"
name="source">
name="source"
>
<option value="Annas Archive">Annas Archive</option>
<option value="LibGen Fiction">LibGen Fiction</option>
<option value="LibGen Non-fiction">LibGen Non-fiction</option>
@ -34,7 +44,8 @@
{{ template "component/button" (dict
"Title" "Search"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
{{ if .SearchErrorMessage }}
@ -42,21 +53,43 @@
{{ end }}
</div>
<div class="inline-block min-w-full overflow-hidden rounded shadow">
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm md:text-sm">
<table
class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm md:text-sm"
>
<thead class="text-gray-800 dark:text-gray-400">
<tr>
<th scope="col"
class="w-12 p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"></th>
<th scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
<th scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Series</th>
<th scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Type</th>
<th scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Size</th>
<th scope="col"
class="p-3 hidden md:block font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
<th
scope="col"
class="w-12 p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
></th>
<th
scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Document
</th>
<th
scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Series
</th>
<th
scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Type
</th>
<th
scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Size
</th>
<th
scope="col"
class="p-3 hidden md:block font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Date
</th>
</tr>
@ -66,29 +99,42 @@
<tr>
<td class="text-center p-3" colspan="6">No Results</td>
</tr>
{{ end }} {{ range $item := .Data }}
{{ end }}
{{ range $item := .Data }}
<tr>
<td class="p-3 border-b border-gray-200 text-gray-500 dark:text-gray-500">
<td
class="p-3 border-b border-gray-200 text-gray-500 dark:text-gray-500"
>
<form action="./search" method="POST">
<input class="hidden"
<input
class="hidden"
type="text"
id="source"
name="source"
value="{{ $.Source }}" />
<input class="hidden"
value="{{ $.Source }}"
/>
<input
class="hidden"
type="text"
id="title"
name="title"
value="{{ $item.Title }}" />
<input class="hidden"
value="{{ $item.Title }}"
/>
<input
class="hidden"
type="text"
id="author"
name="author"
value="{{ $item.Author }}" />
<button name="id" value="{{ $item.ID }}">{{ template "svg/download" }}</button>
value="{{ $item.Author }}"
/>
<button name="id" value="{{ $item.ID }}">
{{ template "svg/download" }}
</button>
</form>
</td>
<td class="p-3 border-b border-gray-200">{{ $item.Author }} - {{ $item.Title }}</td>
<td class="p-3 border-b border-gray-200">
{{ $item.Author }} - {{ $item.Title }}
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ or $item.Series "N/A" }}</p>
</td>

View File

@ -4,46 +4,61 @@
{{ define "content" }}
<div class="w-full flex flex-col md:flex-row gap-4">
<div>
<div class="flex flex-col p-4 items-center rounded shadow-lg md:w-60 lg:w-80 bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col p-4 items-center rounded shadow-lg md:w-60 lg:w-80 bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
{{ template "svg/user" (dict "Size" 60) }}
<p class="text-lg">{{ .Authorization.UserName }}</p>
</div>
</div>
<div class="flex flex-col gap-4 grow">
<div class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<p class="text-lg font-semibold mb-2">Change Password</p>
<form class="flex gap-4 flex-col lg:flex-row"
<form
class="flex gap-4 flex-col lg:flex-row"
action="./settings"
method="POST">
method="POST"
>
<div class="flex flex-col grow">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/password" (dict "Size" 15) }}
</span>
<input type="password"
<input
type="password"
id="password"
name="password"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="Password" />
placeholder="Password"
/>
</div>
</div>
<div class="flex flex-col grow">
<div class="flex relative">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/password" (dict "Size" 15) }}
</span>
<input type="password"
<input
type="password"
id="new_password"
name="new_password"
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
placeholder="New Password" />
placeholder="New Password"
/>
</div>
</div>
<div class="lg:w-60">
{{ template "component/button" (dict
"Title" "Submit"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
{{ if .PasswordErrorMessage }}
@ -52,20 +67,31 @@
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
{{ end }}
</div>
<div class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<p class="text-lg font-semibold mb-2">Change Timezone</p>
<form class="flex gap-4 flex-col lg:flex-row"
<form
class="flex gap-4 flex-col lg:flex-row"
action="./settings"
method="POST">
method="POST"
>
<div class="flex relative grow">
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
<span
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
>
{{ template "svg/clock" (dict "Size" 15) }}
</span>
<select class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
<select
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
id="timezone"
name="timezone">
name="timezone"
>
{{ range $item := getTimeZones }}
<option {{ if (eq $item $.Data.Timezone) }}selected{{ end }} value="{{ $item }}">
<option
{{ if (eq $item $.Data.Timezone) }}selected{{ end }}
value="{{ $item }}"
>
{{ $item }}
</option>
{{ end }}
@ -75,30 +101,43 @@
{{ template "component/button" (dict
"Title" "Submit"
"Variant" "Secondary"
) }}
)
}}
</div>
</form>
{{ if .TimeOffsetErrorMessage }}
<span class="text-red-400 text-xs">{{ .TimeOffsetErrorMessage }}</span>
<span class="text-red-400 text-xs"
>{{ .TimeOffsetErrorMessage }}</span
>
{{ else if .TimeOffsetMessage }}
<span class="text-green-400 text-xs">{{ .TimeOffsetMessage }}</span>
{{ end }}
</div>
<div class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
<div
class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
>
<p class="text-lg font-semibold">Devices</p>
<table class="min-w-full bg-white dark:bg-gray-700 text-sm">
<thead class="text-gray-800 dark:text-gray-400">
<tr>
<th scope="col"
class="p-3 pl-0 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
<th
scope="col"
class="p-3 pl-0 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Name
</th>
<th scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
<th
scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Last Sync
</th>
<th scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Created</th>
<th
scope="col"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
>
Created
</th>
</tr>
</thead>
<tbody class="text-black dark:text-white">