chore(prettier): format templates
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Evan Reichard 2024-06-16 17:11:03 -04:00
parent f37bff365f
commit 9809a09d2e
22 changed files with 1749 additions and 1120 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,26 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" <meta
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" /> 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-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" <meta
content="black-translucent" /> name="apple-mobile-web-app-status-bar-style"
<meta name="theme-color" content="black-translucent"
content="#F3F4F6" />
media="(prefers-color-scheme: light)" /> <meta
<meta name="theme-color" name="theme-color"
content="#1F2937" content="#F3F4F6"
media="(prefers-color-scheme: dark)" /> media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#1F2937"
media="(prefers-color-scheme: dark)"
/>
<title>AnthoLume - {{ block "title" . }}{{ end }}</title> <title>AnthoLume - {{ block "title" . }}{{ end }}</title>
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<link rel="stylesheet" href="/assets/style.css" /> <link rel="stylesheet" href="/assets/style.css" />
@ -32,7 +40,8 @@
html { html {
height: calc(100% + env(safe-area-inset-bottom)); 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 { main {
@ -57,12 +66,12 @@
/* ----------------------------- */ /* ----------------------------- */
/* -------- CSS Button -------- */ /* -------- CSS Button -------- */
/* ----------------------------- */ /* ----------------------------- */
.css-button:checked+div { .css-button:checked + div {
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
} }
.css-button+div { .css-button + div {
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
} }
@ -70,7 +79,7 @@
/* ----------------------------- */ /* ----------------------------- */
/* ------- User Dropdown ------- */ /* ------- User Dropdown ------- */
/* ----------------------------- */ /* ----------------------------- */
#user-dropdown-button:checked+#user-dropdown { #user-dropdown-button:checked + #user-dropdown {
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
} }
@ -99,26 +108,26 @@
transform-origin: 0% 100%; transform-origin: 0% 100%;
} }
#mobile-nav-button input:checked~span { #mobile-nav-button input:checked ~ span {
opacity: 1; opacity: 1;
transform: rotate(45deg) translate(2px, -2px); transform: rotate(45deg) translate(2px, -2px);
} }
#mobile-nav-button input:checked~span:nth-last-child(3) { #mobile-nav-button input:checked ~ span:nth-last-child(3) {
opacity: 0; opacity: 0;
transform: rotate(0deg) scale(0.2, 0.2); transform: rotate(0deg) scale(0.2, 0.2);
} }
#mobile-nav-button input:checked~span:nth-last-child(2) { #mobile-nav-button input:checked ~ span:nth-last-child(2) {
transform: rotate(-45deg) translate(0, 6px); transform: rotate(-45deg) translate(0, 6px);
} }
#mobile-nav-button input:checked~div { #mobile-nav-button input:checked ~ div {
transform: none; transform: none;
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
#mobile-nav-button input~div { #mobile-nav-button input ~ div {
transform: none; transform: none;
} }
} }
@ -133,8 +142,10 @@
@media (orientation: landscape) { @media (orientation: landscape) {
#menu { #menu {
transform: translate(calc(-1 * (env(safe-area-inset-left) + 100%)), transform: translate(
0); calc(-1 * (env(safe-area-inset-left) + 100%)),
0
);
} }
} }
</style> </style>
@ -142,141 +153,243 @@
<body class="bg-gray-100 dark:bg-gray-800"> <body class="bg-gray-100 dark:bg-gray-800">
<div class="flex items-center justify-between w-full h-16"> <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"> <div id="mobile-nav-button" class="flex flex-col z-40 relative ml-6">
<input type="checkbox" <input
class="absolute lg:hidden z-50 -top-2 w-7 h-7 flex cursor-pointer opacity-0" /> type="checkbox"
<span class="lg:hidden bg-black w-7 h-0.5 z-40 mt-0.5 dark:bg-white"></span> 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-1 dark:bg-white"></span> />
<span class="lg:hidden bg-black w-7 h-0.5 z-40 mt-1 dark:bg-white"></span> <span
<div id="menu" class="lg:hidden bg-black w-7 h-0.5 z-40 mt-0.5 dark:bg-white"
class="fixed -ml-6 h-full w-56 lg:w-48 bg-white dark:bg-gray-700 shadow-lg"> ></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"> <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>
<div> <div>
{{ $default := "flex items-center justify-start w-full p-2 pl-6 my-2 transition-colors duration-200 border-l-4" }} {{ $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" }} {{ $inactive := "border-transparent text-gray-400 hover:text-gray-800 dark:hover:text-gray-100" }}
{{ $active := "border-purple-500 dark:text-white" }} {{ $active := "border-purple-500 dark:text-white" }}
<a class="{{ $default }} {{ if eq .RouteName "home" }} {{ $active }} {{ else if true }} {{ $inactive }} {{ end }}" <a
href="/"> class="{{ $default }} {{ if eq .RouteName "home" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/"
>
{{ template "svg/home" (dict "Size" 20) }} {{ template "svg/home" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Home</span> <span class="mx-4 text-sm font-normal">Home</span>
</a> </a>
<a class="{{ $default }} {{ if eq .RouteName "documents" }} {{ $active }} {{ else if true }} {{ $inactive }} {{ end }}" <a
href="/documents"> class="{{ $default }} {{ if eq .RouteName "documents" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/documents"
>
{{ template "svg/documents" (dict "Size" 20) }} {{ template "svg/documents" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Documents</span> <span class="mx-4 text-sm font-normal">Documents</span>
</a> </a>
<a class="{{ $default }} {{ if eq .RouteName "progress" }} {{ $active }} {{ else if true }} {{ $inactive }} {{ end }}" <a
href="/progress"> class="{{ $default }} {{ if eq .RouteName "progress" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/progress"
>
{{ template "svg/activity" (dict "Size" 20) }} {{ template "svg/activity" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Progress</span> <span class="mx-4 text-sm font-normal">Progress</span>
</a> </a>
<a class="{{ $default }} {{ if eq .RouteName "activity" }} {{ $active }} {{ else if true }} {{ $inactive }} {{ end }}" <a
href="/activity"> class="{{ $default }} {{ if eq .RouteName "activity" }}
{{ $active }}
{{ else if true }}
{{ $inactive }}
{{ end }}"
href="/activity"
>
{{ template "svg/activity" (dict "Size" 20) }} {{ template "svg/activity" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Activity</span> <span class="mx-4 text-sm font-normal">Activity</span>
</a> </a>
{{ if .Config.SearchEnabled }} {{ if .Config.SearchEnabled }}
<a class="{{ $default }} {{ if eq .RouteName "search" }} {{ $active }} {{ else if true }} {{ $inactive }} {{ end }}" <a
href="/search"> class="{{ $default }} {{ if eq .RouteName "search" }}
{{ template "svg/search" (dict "Size" 20) }} {{ $active }}
<span class="mx-4 text-sm font-normal">Search</span> {{ else if true }}
</a> {{ $inactive }}
{{ end }}"
href="/search"
>
{{ template "svg/search" (dict "Size" 20) }}
<span class="mx-4 text-sm font-normal">Search</span>
</a>
{{ end }} {{ end }}
{{ if .Authorization.IsAdmin }} {{ 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 }}"> <div
<a href="/admin" class="flex flex-col gap-4 p-2 pl-6 my-2 transition-colors duration-200 border-l-4 {{ if hasPrefix .RouteName "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 }}"> dark:text-white border-purple-500
{{ template "svg/settings" (dict "Size" 20) }} {{ else if true }}
<span class="mx-4 text-sm font-normal">Admin</span> border-transparent text-gray-400
</a> {{ end }}"
{{ if hasPrefix .RouteName "admin" }} >
<a href="/admin" <a
style="padding-left: 1.75em" href="/admin"
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 (hasPrefix .RouteName "admin") }}
<span class="mx-4 text-sm font-normal">General</span> text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
</a> {{ end }}"
<a href="/admin/import" >
style="padding-left: 1.75em" {{ template "svg/settings" (dict "Size" 20) }}
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">Admin</span>
<span class="mx-4 text-sm font-normal">Import</span> </a>
</a> {{ if hasPrefix .RouteName "admin" }}
<a href="/admin/users" <a
style="padding-left: 1.75em" href="/admin"
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 }}"> style="padding-left: 1.75em"
<span class="mx-4 text-sm font-normal">Users</span> class="flex justify-start w-full {{ if not (eq .RouteName "admin") }}
</a> text-gray-400 hover:text-gray-800 dark:hover:text-gray-100
<a href="/admin/logs" {{ end }}"
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 }}"> <span class="mx-4 text-sm font-normal">General</span>
<span class="mx-4 text-sm font-normal">Logs</span> </a>
</a> <a
{{ end }} href="/admin/import"
</div> 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 }}"
>
<span class="mx-4 text-sm font-normal">Import</span>
</a>
<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 }}"
>
<span class="mx-4 text-sm font-normal">Users</span>
</a>
<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 }}"
>
<span class="mx-4 text-sm font-normal">Logs</span>
</a>
{{ end }}
</div>
{{ end }} {{ end }}
</div> </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
target="_blank" class="flex flex-col gap-2 justify-center items-center p-6 w-full absolute bottom-0 text-black dark:text-white"
href="https://gitea.va.reichard.io/evan/AnthoLume"> target="_blank"
<svg xmlns="http://www.w3.org/2000/svg" href="https://gitea.va.reichard.io/evan/AnthoLume"
class="text-black dark:text-white" >
height="20" <svg
viewBox="0 0 219 92" xmlns="http://www.w3.org/2000/svg"
fill="currentColor"> class="text-black dark:text-white"
height="20"
viewBox="0 0 219 92"
fill="currentColor"
>
<defs> <defs>
<clipPath id="a"> <clipPath id="a">
<path d="M159 .79h25V69h-25Zm0 0" /> <path d="M159 .79h25V69h-25Zm0 0" />
</clipPath> </clipPath>
<clipPath id="b"> <clipPath id="b">
<path d="M183 9h35.371v60H183Zm0 0" /> <path d="M183 9h35.371v60H183Zm0 0" />
</clipPath> </clipPath>
<clipPath id="c"> <clipPath id="c">
<path d="M0 .79h92V92H0Zm0 0" /> <path d="M0 .79h92V92H0Zm0 0" />
</clipPath> </clipPath>
</defs> </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)"> <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>
<g clip-path="url(#b)"> <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>
<g clip-path="url(#c)"> <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> </g>
</svg> </svg>
<span class="text-xs">{{ .Config.Version }}</span> <span class="text-xs">{{ .Config.Version }}</span>
</a> </a>
</div> </div>
</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"> <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" /> <input type="checkbox" id="user-dropdown-button" class="hidden" />
<div id="user-dropdown" <div
class="transition duration-200 z-20 absolute right-4 top-16 pt-4"> id="user-dropdown"
<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"> class="transition duration-200 z-20 absolute right-4 top-16 pt-4"
<div class="py-1" >
role="menu" <div
aria-orientation="vertical" 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"
aria-labelledby="options-menu"> >
<a href="/settings" <div
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" class="py-1"
role="menuitem"> role="menu"
aria-orientation="vertical"
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"
>
<span class="flex flex-col"> <span class="flex flex-col">
<span>Settings</span> <span>Settings</span>
</span> </span>
</a> </a>
<a href="/local" <a
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" href="/local"
role="menuitem"> 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"
>
<span class="flex flex-col"> <span class="flex flex-col">
<span>Offline</span> <span>Offline</span>
</span> </span>
</a> </a>
<a href="/logout" <a
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" href="/logout"
role="menuitem"> 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"
>
<span class="flex flex-col"> <span class="flex flex-col">
<span>Logout</span> <span>Logout</span>
</span> </span>
@ -285,15 +398,24 @@
</div> </div>
</div> </div>
<label for="user-dropdown-button"> <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>{{ .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> </div>
</label> </label>
</div> </div>
</div> </div>
<main class="relative overflow-hidden"> <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> </main>
<div class="absolute right-4 bottom-4"> <div class="absolute right-4 bottom-4">
{{ block "notifications" . }}{{ end }} {{ block "notifications" . }}{{ end }}

View File

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

View File

@ -1,8 +1,13 @@
<div class="w-full relative"> <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"> <div class="min-w-fit my-auto h-48 relative">
<a href="./documents/{{.ID}}"> <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> </a>
</div> </div>
<div class="flex flex-col justify-around dark:text-white w-full text-sm"> <div class="flex flex-col justify-around dark:text-white w-full text-sm">
@ -31,12 +36,14 @@
</div> </div>
</div> </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> <a href="./activity?document={{ .ID }}">{{ template "svg/activity" }}</a>
{{ if .Filepath }} {{ if .Filepath }}
<a href="./documents/{{.ID}}/file">{{ template "svg/download" }}</a> <a href="./documents/{{ .ID }}/file">{{ template "svg/download" }}</a>
{{ else }} {{ else }}
{{ template "svg/download" (dict "Disabled" true) }} {{ template "svg/download" (dict "Disabled" true) }}
{{ end }} {{ end }}
</div> </div>
</div> </div>

View File

@ -1,22 +1,42 @@
<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"> <div
<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 }}"> 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) }} {{ if and (ne .Progress 100) (not .Error) }}
{{ template "svg/loading" (dict "Size" 16) }} {{ template "svg/loading" (dict "Size" 16) }}
{{ end }} {{ end }}
{{ .Message }} {{ .Message }}
</span> </span>
<div class="flex flex-col gap-2 mt-2"> <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"> <div class="relative w-full h-4 bg-gray-300 dark:bg-gray-700 rounded-full">
{{ if .Error }} {{ if .Error }}
<div class="absolute h-full bg-red-500 rounded-full" style="width: 100%"></div> <div
<p class="absolute w-full h-full font-bold text-center text-xs">ERROR</p> 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 }} {{ else }}
<div class="absolute h-full bg-green-600 rounded-full" <div
style="width: {{ .Progress }}%"></div> class="absolute h-full bg-green-600 rounded-full"
<p class="absolute w-full h-full font-bold text-center text-xs">{{ .Progress }}%</p> style="width: {{ .Progress }}%"
></div>
<p class="absolute w-full h-full font-bold text-center text-xs">
{{ .Progress }}%
</p>
{{ end }} {{ end }}
</div> </div>
<a href="{{ .ButtonHref }}" <a
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> 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>
</div> </div>

View File

@ -4,14 +4,26 @@
<label class="my-auto cursor-pointer" for="edit-{{ .FormValue }}-button"> <label class="my-auto cursor-pointer" for="edit-{{ .FormValue }}-button">
{{ template "svg/edit" (dict "Size" 18) }} {{ template "svg/edit" (dict "Size" 18) }}
</label> </label>
<input type="checkbox" <input
id="edit-{{ .FormValue }}-button" type="checkbox"
class="hidden css-button" /> id="edit-{{ .FormValue }}-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"> class="hidden css-button"
<form method="POST" />
action="{{ .URL }}" <div
class="flex flex-col gap-2 text-black dark:text-white text-sm"> 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"
<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" /> >
<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"
/>
{{ template "component/button" (dict "Title" "Save") }} {{ template "component/button" (dict "Title" "Save") }}
</form> </form>
</div> </div>

View File

@ -1,102 +1,147 @@
{{ if .Error }} {{ if .Error }}
<div class="absolute top-0 left-0 w-full h-full z-50"> <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="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
<div class="text-center"> 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"
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">No Metadata Results Found</h3> >
</div> <div class="text-center">
{{ template "component/button" (dict <h3 class="text-lg font-bold leading-6 dark:text-gray-300">
"Title" "Back to Document" No Metadata Results Found
"Type" "Link" </h3>
"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="py-5 text-center">
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">Metadata Results</h3>
</div>
<form id="metadata-save"
method="POST"
action="/documents/{{ .ID }}/edit"
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">
<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" />
</dd>
</div>
<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">
<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">
<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">
<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">
<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" }}
</dd>
</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"
id="description"
name="description"
value="{{ .Metadata.Description }}" />
<input type="text"
id="isbn_10"
name="isbn_10"
value="{{ .Metadata.ISBN10 }}" />
<input type="text"
id="isbn_13"
name="isbn_13"
value="{{ .Metadata.ISBN13 }}" />
<input type="text"
id="cover_gbid"
name="cover_gbid"
value="{{ .Metadata.ID }}" />
</div> </div>
</form> {{ template "component/button" (dict
<div class="flex justify-end"> "Title" "Back to Document"
<div class="flex gap-4 m-4 w-48">
{{ template "component/button" (dict
"Title" "Cancel"
"Type" "Link" "Type" "Link"
"URL" (printf "/documents/%s" .ID) "URL" (printf "/documents/%s" .ID)
)}} )
{{ template "component/button" (dict }}
"Title" "Save" </div>
"FormName" "metadata-save" </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="py-5 text-center">
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">
Metadata Results
</h3>
</div>
<form
id="metadata-save"
method="POST"
action="/documents/{{ .ID }}/edit"
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"
>
<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"
/>
</dd>
</div>
<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"
>
<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"
>
<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"
>
<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"
>
<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" }}
</dd>
</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"
id="description"
name="description"
value="{{ .Metadata.Description }}"
/>
<input
type="text"
id="isbn_10"
name="isbn_10"
value="{{ .Metadata.ISBN10 }}"
/>
<input
type="text"
id="isbn_13"
name="isbn_13"
value="{{ .Metadata.ISBN13 }}"
/>
<input
type="text"
id="cover_gbid"
name="cover_gbid"
value="{{ .Metadata.ID }}"
/>
</div>
</form>
<div class="flex justify-end">
<div class="flex gap-4 m-4 w-48">
{{ template "component/button" (dict
"Title" "Cancel"
"Type" "Link"
"URL" (printf "/documents/%s" .ID)
)
}}
{{ template "component/button" (dict
"Title" "Save"
"FormName" "metadata-save"
)
}}
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
{{ end }} {{ end }}

View File

@ -1,23 +1,36 @@
<div class="w-full"> <div class="w-full">
<div class="relative w-full px-4 py-6 bg-white shadow-lg dark:bg-gray-700 rounded"> <div
<p class="text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500"> 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" }} {{ if eq .Window "WEEK" }}
Weekly Read Streak Weekly Read Streak
{{ else }} {{ else }}
Daily Read Streak Daily Read Streak
{{ end }} {{ end }}
</p> </p>
<div class="flex items-end my-6 space-x-2"> <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>
<div class="dark:text-white"> <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> <div>
<p> <p>
{{ if eq .Window "WEEK" }} Current Weekly Streak {{ else }} {{ if eq .Window "WEEK" }}
Current Daily Streak {{ end }} Current Weekly Streak
{{ else }}
Current Daily Streak
{{ end }}
</p> </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>
<div class="flex items-end font-bold">{{ .CurrentStreak }}</div> <div class="flex items-end font-bold">{{ .CurrentStreak }}</div>
</div> </div>
@ -25,12 +38,14 @@
<div> <div>
<p> <p>
{{ if eq .Window "WEEK" }} {{ if eq .Window "WEEK" }}
Best Weekly Streak Best Weekly Streak
{{ else }} {{ else }}
Best Daily Streak Best Daily Streak
{{ end }} {{ end }}
</p> </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>
<div class="flex items-end font-bold">{{ .MaxStreak }}</div> <div class="flex items-end font-bold">{{ .MaxStreak }}</div>
</div> </div>

View File

@ -5,22 +5,28 @@
<thead class="text-gray-800 dark:text-gray-400"> <thead class="text-gray-800 dark:text-gray-400">
<tr> <tr>
{{ range $col := $cols }} {{ 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 }} {{ end }}
</tr> </tr>
</thead> </thead>
<tbody class="text-black dark:text-white"> <tbody class="text-black dark:text-white">
{{ if not $rows }} {{ if not $rows }}
<tr> <tr>
<td class="text-center p-3" colspan="4">No Results</td> <td class="text-center p-3" colspan="4">No Results</td>
</tr> </tr>
{{ end }} {{ end }}
{{ range $row := $rows }} {{ range $row := $rows }}
<tr> <tr>
{{ range $key := $keys }} {{ range $key := $keys }}
<td class="p-3 border-b border-gray-200">{{ template "table-cell" (dict "Data" $row "Name" $key )}}</td> <td class="p-3 border-b border-gray-200">
{{ end }} {{ template "table-cell" (dict "Data" $row "Name" $key ) }}
</tr> </td>
{{ end }}
</tr>
{{ end }} {{ end }}
</tbody> </tbody>
</table> </table>

View File

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

View File

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

View File

@ -1,79 +1,111 @@
{{ template "base" . }} {{ template "base" . }}
{{ define "title" }}Admin - Import{{ end }} {{ define "title" }}Admin - Import{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Import</a>{{ end }} {{ define "header" }}
{{ define "content" }} <a class="whitespace-pre" href="../admin">Admin - Import</a>
<div class="overflow-x-auto"> {{ end }}
<div class="inline-block min-w-full overflow-hidden rounded shadow"> {{ define "content" }}
{{ if .SelectedDirectory }} <div class="overflow-x-auto">
<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="inline-block min-w-full overflow-hidden rounded shadow">
<p class="text-lg font-semibold text-gray-500">Selected Import Directory</p> {{ if .SelectedDirectory }}
<form class="flex gap-4 flex-col" action="./import" method="POST"> <div
<input type="text" class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
name="directory" >
value="{{ .SelectedDirectory }}" <p class="text-lg font-semibold text-gray-500">
class="hidden" /> Selected Import Directory
<div class="flex justify-between gap-4 w-full"> </p>
<div class="flex gap-4 items-center"> <form class="flex gap-4 flex-col" action="./import" method="POST">
<span>{{ template "svg/import" }}</span> <input
<p class="font-medium text-lg break-all">{{ .SelectedDirectory }}</p> type="text"
</div> name="directory"
<div class="flex flex-col justify-around gap-2 mr-4"> value="{{ .SelectedDirectory }}"
<div class="inline-flex gap-2 items-center"> class="hidden"
<input checked type="radio" id="direct" name="type" value="DIRECT" /> />
<label for="direct">Direct</label> <div class="flex justify-between gap-4 w-full">
</div> <div class="flex gap-4 items-center">
<div class="inline-flex gap-2 items-center"> <span>{{ template "svg/import" }}</span>
<input type="radio" id="copy" name="type" value="COPY" /> <p class="font-medium text-lg break-all">
<label for="copy">Copy</label> {{ .SelectedDirectory }}
</div> </p>
</div> </div>
</div> <div class="flex flex-col justify-around gap-2 mr-4">
<button type="submit" <div class="inline-flex gap-2 items-center">
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"> <input
<span class="w-full">Import Directory</span> checked
</button> type="radio"
</form> id="direct"
</div> name="type"
{{ end }} value="DIRECT"
{{ if not .SelectedDirectory }} />
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm"> <label for="direct">Direct</label>
<thead class="text-gray-800 dark:text-gray-400"> </div>
<tr> <div class="inline-flex gap-2 items-center">
<th class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 w-12"></th> <input type="radio" id="copy" name="type" value="COPY" />
<th class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 break-all">{{ .CurrentPath }}</th> <label for="copy">Copy</label>
</tr> </div>
</thead> </div>
<tbody class="text-black dark:text-white"> </div>
{{ if not (eq .CurrentPath "/") }} <button
<tr> type="submit"
<td class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400"></td> 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"
<td class="p-3 border-b border-gray-200"> >
<a href="./import?directory={{$.CurrentPath}}/../"> <span class="w-full">Import Directory</span>
<p>../</p> </button>
</a> </form>
</td> </div>
</tr> {{ end }}
{{ end }} {{ if not .SelectedDirectory }}
{{ if not .Data }} <table
<tr> class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm"
<td class="text-center p-3" colspan="2">No Folders</td> >
</tr> <thead class="text-gray-800 dark:text-gray-400">
{{ end }} <tr>
{{ range $item := .Data }} <th
<tr> class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 w-12"
<td class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400"> ></th>
<a href="./import?select={{ $.CurrentPath }}/{{ $item }}">{{ template "svg/import" }}</a> <th
</td> class="p-3 font-normal text-left border-b border-gray-200 dark:border-gray-800 break-all"
<td class="p-3 border-b border-gray-200"> >
<a href="./import?directory={{ $.CurrentPath }}/{{ $item }}"> {{ .CurrentPath }}
<p>{{ $item }}</p> </th>
</a> </tr>
</td> </thead>
</tr> <tbody class="text-black dark:text-white">
{{ end }} {{ if not (eq .CurrentPath "/") }}
</tbody> <tr>
</table> <td
{{ end }} class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400"
</div> ></td>
</div> <td class="p-3 border-b border-gray-200">
<a href="./import?directory={{ $.CurrentPath }}/../">
<p>../</p>
</a>
</td>
</tr>
{{ end }}
{{ if not .Data }}
<tr>
<td class="text-center p-3" colspan="2">No Folders</td>
</tr>
{{ 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>
<td class="p-3 border-b border-gray-200">
<a href="./import?directory={{ $.CurrentPath }}/{{ $item }}">
<p>{{ $item }}</p>
</a>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
</div>
</div>
{{ end }} {{ end }}

View File

@ -1,36 +1,47 @@
{{ template "base" . }} {{ template "base" . }}
{{ define "title" }}Admin - Logs{{ end }} {{ define "title" }}Admin - Logs{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Logs</a>{{ end }} {{ define "header" }}
{{ define "content" }} <a class="whitespace-pre" href="../admin">Admin - Logs</a>
<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"> {{ end }}
<form class="flex gap-4 flex-col lg:flex-row" action="./logs" method="GET"> {{ define "content" }}
<div class="flex flex-col w-full grow"> <div
<div class="flex relative"> 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"
<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) }} <form class="flex gap-4 flex-col lg:flex-row" action="./logs" method="GET">
</span> <div class="flex flex-col w-full grow">
<input type="text" <div class="flex relative">
id="filter" <span
name="filter" 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"
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" {{ template "svg/search2" (dict "Size" 15) }}
placeholder="JQ Filter" /> </span>
</div> <input
</div> type="text"
<div class="lg:w-60"> id="filter"
{{ template "component/button" (dict name="filter"
"Title" "Filter" value="{{ .Filter }}"
"Variant" "Secondary" 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"
</div> />
</form> </div>
</div> </div>
<!-- Required for iOS "Hover" Events (onclick) --> <div class="lg:w-60">
<div onclick {{ template "component/button" (dict
class="flex flex-col-reverse text-black dark:text-white w-full overflow-scroll" "Title" "Filter"
style="font-family: monospace"> "Variant" "Secondary"
{{ range $log := .Data }} )
<span class="whitespace-nowrap hover:whitespace-pre">{{ $log }}</span> }}
{{ end }} </div>
</div> </form>
</div>
<!-- Required for iOS "Hover" Events (onclick) -->
<div
onclick
class="flex flex-col-reverse text-black dark:text-white w-full overflow-scroll"
style="font-family: monospace"
>
{{ range $log := .Data }}
<span class="whitespace-nowrap hover:whitespace-pre">{{ $log }}</span>
{{ end }}
</div>
{{ end }} {{ end }}

View File

@ -1,93 +1,127 @@
{{ template "base" . }} {{ template "base" . }}
{{ define "title" }}Admin - General{{ end }} {{ define "title" }}Admin - General{{ end }}
{{ define "header" }}<a class="whitespace-pre" href="./admin">Admin - General</a>{{ end }} {{ define "header" }}
{{ define "content" }} <a class="whitespace-pre" href="./admin">Admin - General</a>
<div class="w-full flex flex-col gap-4 grow"> {{ end }}
<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"> {{ define "content" }}
<p class="text-lg font-semibold mb-2">Backup & Restore</p> <div class="w-full flex flex-col gap-4 grow">
<div class="flex flex-col gap-4"> <div
<form class="flex justify-between" action="./admin" method="POST"> class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
<input type="text" name="action" value="BACKUP" class="hidden" /> >
<div class="flex gap-8 items-center"> <p class="text-lg font-semibold mb-2">Backup & Restore</p>
<div> <div class="flex flex-col gap-4">
<input type="checkbox" id="backup_covers" name="backup_types" value="COVERS" /> <form class="flex justify-between" action="./admin" method="POST">
<label for="backup_covers">Covers</label> <input type="text" name="action" value="BACKUP" class="hidden" />
</div> <div class="flex gap-8 items-center">
<div> <div>
<input type="checkbox" <input
id="backup_documents" type="checkbox"
name="backup_types" id="backup_covers"
value="DOCUMENTS" /> name="backup_types"
<label for="backup_documents">Documents</label> value="COVERS"
</div> />
</div> <label for="backup_covers">Covers</label>
<div class="w-40 h-10"> </div>
{{ template "component/button" (dict <div>
"Title" "Backup" <input
"Variant" "Secondary" type="checkbox"
) }} id="backup_documents"
</div> name="backup_types"
</form> value="DOCUMENTS"
<form method="POST" />
enctype="multipart/form-data" <label for="backup_documents">Documents</label>
action="./admin" </div>
class="flex justify-between grow"> </div>
<input type="text" name="action" value="RESTORE" class="hidden" /> <div class="w-40 h-10">
<div class="flex items-center w-1/2"> {{ template "component/button" (dict
<input type="file" accept=".zip" name="restore_file" class="w-full" /> "Title" "Backup"
</div> "Variant" "Secondary"
<div class="w-40 h-10"> )
{{ template "component/button" (dict }}
"Title" "Restore" </div>
"Variant" "Secondary" </form>
) }} <form
</div> method="POST"
</form> enctype="multipart/form-data"
</div> action="./admin"
{{ if .PasswordErrorMessage }} class="flex justify-between grow"
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span> >
{{ else if .PasswordMessage }} <input type="text" name="action" value="RESTORE" class="hidden" />
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span> <div class="flex items-center w-1/2">
{{ end }} <input
</div> type="file"
<div class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"> accept=".zip"
<p class="text-lg font-semibold">Tasks</p> name="restore_file"
<table class="min-w-full bg-white dark:bg-gray-700 text-sm"> class="w-full"
<tbody class="text-black dark:text-white"> />
<tr> </div>
<td class="pl-0"> <div class="w-40 h-10">
<p>Metadata Matching</p> {{ template "component/button" (dict
</td> "Title" "Restore"
<td class="py-2 float-right"> "Variant" "Secondary"
<form action="./admin" method="POST"> )
<input type="text" name="action" value="METADATA_MATCH" class="hidden" /> }}
<div class="w-40 h-10 text-base"> </div>
{{ template "component/button" (dict </form>
"Title" "Run" </div>
"Variant" "Secondary" {{ if .PasswordErrorMessage }}
) }} <span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
</div> {{ else if .PasswordMessage }}
</form> <span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
</td> {{ end }}
</tr> </div>
<tr> <div
<td> class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
<p>Cache Tables</p> >
</td> <p class="text-lg font-semibold">Tasks</p>
<td class="py-2 float-right"> <table class="min-w-full bg-white dark:bg-gray-700 text-sm">
<form action="./admin" method="POST"> <tbody class="text-black dark:text-white">
<input type="text" name="action" value="CACHE_TABLES" class="hidden" /> <tr>
<div class="w-40 h-10 text-base"> <td class="pl-0">
{{ template "component/button" (dict <p>Metadata Matching</p>
"Title" "Run" </td>
"Variant" "Secondary" <td class="py-2 float-right">
) }} <form action="./admin" method="POST">
</div> <input
</form> type="text"
</td> name="action"
</tr> value="METADATA_MATCH"
</tbody> class="hidden"
</table> />
</div> <div class="w-40 h-10 text-base">
</div> {{ template "component/button" (dict
"Title" "Run"
"Variant" "Secondary"
)
}}
</div>
</form>
</td>
</tr>
<tr>
<td>
<p>Cache Tables</p>
</td>
<td class="py-2 float-right">
<form action="./admin" method="POST">
<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>
</tr>
</tbody>
</table>
</div>
</div>
{{ end }} {{ end }}

View File

@ -2,169 +2,253 @@
{{ define "title" }}Documents{{ end }} {{ define "title" }}Documents{{ end }}
{{ define "header" }}<a href="/documents">Documents</a>{{ end }} {{ define "header" }}<a href="/documents">Documents</a>{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="h-full w-full relative"> <div class="h-full w-full relative">
<!-- Document Info --> <!-- 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
<div class="flex flex-col gap-2 float-left w-44 md:w-60 lg:w-80 mr-4 mb-2 relative"> class="h-full w-full overflow-scroll bg-white shadow-lg dark:bg-gray-700 rounded dark:text-white p-4"
<label class="z-10 cursor-pointer" for="edit-cover-button"> >
<img class="rounded object-fill w-full" <div
src="/documents/{{.Data.ID}}/cover" /> class="flex flex-col gap-2 float-left w-44 md:w-60 lg:w-80 mr-4 mb-2 relative"
</label> >
{{ if .Data.Filepath }} <label class="z-10 cursor-pointer" for="edit-cover-button">
<a href="/reader#id={{ .Data.ID }}&type=REMOTE" <img
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> class="rounded object-fill w-full"
{{ end }} src="/documents/{{ .Data.ID }}/cover"
<div class="flex flex-wrap-reverse justify-between z-20 gap-2 relative"> />
<div class="min-w-[50%] md:mr-2"> </label>
<div class="flex gap-1 text-sm"> {{ if .Data.Filepath }}
<p class="text-gray-500">ISBN-10:</p> <a
<p class="font-medium">{{ or .Data.Isbn10 "N/A" }}</p> href="/reader#id={{ .Data.ID }}&type=REMOTE"
</div> 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"
<div class="flex gap-1 text-sm"> >Read</a
<p class="text-gray-500">ISBN-13:</p> >
<p class="font-medium">{{ or .Data.Isbn13 "N/A" }}</p> {{ end }}
</div> <div class="flex flex-wrap-reverse justify-between z-20 gap-2 relative">
</div> <div class="min-w-[50%] md:mr-2">
<div class="flex grow justify-between my-auto text-gray-500 dark:text-gray-500"> <div class="flex gap-1 text-sm">
<input type="checkbox" id="edit-cover-button" class="hidden css-button" /> <p class="text-gray-500">ISBN-10:</p>
<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"> <p class="font-medium">{{ or .Data.Isbn10 "N/A" }}</p>
<form method="POST" </div>
enctype="multipart/form-data" <div class="flex gap-1 text-sm">
action="./{{ .Data.ID }}/edit" <p class="text-gray-500">ISBN-13:</p>
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm"> <p class="font-medium">{{ or .Data.Isbn13 "N/A" }}</p>
<input type="file" id="cover_file" name="cover_file">
{{ template "component/button" (dict "Title" "Upload Cover") }}
</form>
<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"
checked
id="remove_cover"
name="remove_cover"
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"
action="./{{ .Data.ID }}/delete"
class="text-black dark:text-white text-sm w-24">
{{ template "component/button" (dict "Title" "Delete") }}
</form>
</div> </div>
</div> </div>
<a href="../activity?document={{ .Data.ID }}">{{ template "svg/activity" (dict "Size" 28) }}</a> <div
<div class="relative"> class="flex grow justify-between my-auto text-gray-500 dark:text-gray-500"
<label for="search-button">{{ template "svg/search" (dict "Size" 28) }}</label> >
<input type="checkbox" id="search-button" class="hidden css-button" /> <input
<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"> type="checkbox"
<form method="POST" id="edit-cover-button"
action="./{{ .Data.ID }}/identify" class="hidden css-button"
class="flex flex-col gap-2 text-black dark:text-white text-sm"> />
<input type="text" <div
id="title" 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"
name="title" >
placeholder="Title" <form
value="{{ or .Data.Title nil }}" method="POST"
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"> enctype="multipart/form-data"
<input type="text" action="./{{ .Data.ID }}/edit"
id="author" class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm"
name="author" >
placeholder="Author" <input type="file" id="cover_file" name="cover_file" />
value="{{ or .Data.Author nil }}" {{ template "component/button" (dict "Title" "Upload Cover") }}
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"> </form>
<input type="text" <form
id="isbn" method="POST"
name="isbn" action="./{{ .Data.ID }}/edit"
placeholder="ISBN 10 / ISBN 13" class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm"
value="{{ or .Data.Isbn13 (or .Data.Isbn10 nil) }}" >
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"> <input
{{ template "component/button" (dict "Title" "Identify") }} type="checkbox"
checked
id="remove_cover"
name="remove_cover"
class="hidden"
/>
{{ template "component/button" (dict "Title" "Remove Cover") }}
</form> </form>
</div> </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"
action="./{{ .Data.ID }}/delete"
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
>
<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"
action="./{{ .Data.ID }}/identify"
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"
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"
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"
/>
{{ template "component/button" (dict "Title" "Identify") }}
</form>
</div>
</div>
{{ if .Data.Filepath }}
<a href="./{{ .Data.ID }}/file"
>{{ template "svg/download" (dict "Size" 28) }}</a
>
{{ else }}
{{ template "svg/download" (dict "Size" 28 "Disabled" true) }}
{{ end }}
</div> </div>
{{ if .Data.Filepath }}
<a href="./{{.Data.ID}}/file">{{ template "svg/download" (dict "Size" 28) }}</a>
{{ else }}
{{ template "svg/download" (dict "Size" 28 "Disabled" true) }}
{{ end }}
</div> </div>
</div> </div>
</div> <div class="grid sm:grid-cols-2 justify-between gap-4 pb-4">
<div class="grid sm:grid-cols-2 justify-between gap-4 pb-4"> {{ template "component/key-val-edit" (dict
{{ template "component/key-val-edit" (dict "Title" "Title"
"Title" "Title" "Value" .Data.Title
"Value" .Data.Title "URL" (printf "./%s/edit" .Data.ID)
"URL" (printf "./%s/edit" .Data.ID) "FormValue" "title"
"FormValue" "title" )
)}} }}
{{ template "component/key-val-edit" (dict {{ template "component/key-val-edit" (dict
"Title" "Author" "Title" "Author"
"Value" .Data.Author "Value" .Data.Author
"URL" (printf "./%s/edit" .Data.ID) "URL" (printf "./%s/edit" .Data.ID)
"FormValue" "author" "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"
>
<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>
</div>
<div class="text-xs flex">
<p class="text-gray-400 w-32">Words / Minute</p>
<p class="font-medium dark:text-white">{{ .Data.Wpm }}</p>
</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>
</div>
</div>
</div>
<p class="font-medium text-lg">
{{ niceSeconds .Data.TotalTimeSeconds }}
</p>
</div>
<div>
<p class="text-gray-500">Progress</p>
<p class="font-medium text-lg">{{ .Data.Percentage }}%</p>
</div>
</div>
<div class="relative"> <div class="relative">
<div class="text-gray-500 inline-flex gap-2 relative"> <div class="text-gray-500 inline-flex gap-2 relative">
<p>Time Read</p> <p>Description</p>
<label class="my-auto" for="progress-info-button">{{ template "svg/info" (dict "Size" 18) }}</label> <label class="my-auto" for="edit-description-button"
<input type="checkbox" id="progress-info-button" class="hidden css-button" /> >{{ template "svg/edit" (dict "Size" 18) }}</label
<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>
</div>
<div class="text-xs flex">
<p class="text-gray-400 w-32">Words / Minute</p>
<p class="font-medium dark:text-white">{{ .Data.Wpm }}</p>
</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>
</div>
</div>
</div> </div>
<p class="font-medium text-lg">{{ niceSeconds .Data.TotalTimeSeconds }}</p>
</div> </div>
<div> <div class="relative font-medium text-justify hyphens-auto">
<p class="text-gray-500">Progress</p> <input
<p class="font-medium text-lg">{{ .Data.Percentage }}%</p> 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"
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"
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
>
{{ template "component/button" (dict "Title" "Save") }}
</form>
</div>
<p>{{ or .Data.Description "N/A" }}</p>
</div> </div>
</div> </div>
<div class="relative"> {{ template "component/metadata" (dict
<div class="text-gray-500 inline-flex gap-2 relative"> "ID" .Data.ID
<p>Description</p> "Metadata" .Metadata
<label class="my-auto" for="edit-description-button">{{ template "svg/edit" (dict "Size" 18) }}</label> "Error" .MetadataError
</div> )
</div> }}
<div class="relative font-medium text-justify hyphens-auto">
<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"
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"
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>
{{ template "component/button" (dict "Title" "Save") }}
</form>
</div>
<p>{{ or .Data.Description "N/A" }}</p>
</div>
</div> </div>
{{ template "component/metadata" (dict
"ID" .Data.ID
"Metadata" .Metadata
"Error" .MetadataError
)}}
</div>
{{ end }} {{ end }}

View File

@ -2,63 +2,98 @@
{{ define "title" }}Documents{{ end }} {{ define "title" }}Documents{{ end }}
{{ define "header" }}<a href="./documents">Documents</a>{{ end }} {{ define "header" }}<a href="./documents">Documents</a>{{ end }}
{{ define "content" }} {{ 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
<form class="flex gap-4 flex-col lg:flex-row" 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"
action="./documents" >
method="GET"> <form
<div class="flex flex-col w-full grow"> class="flex gap-4 flex-col lg:flex-row"
<div class="flex relative"> action="./documents"
<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"> method="GET"
{{ template "svg/search2" (dict "Size" 15) }} >
</span> <div class="flex flex-col w-full grow">
<input type="text" <div class="flex relative">
id="search" <span
name="search" 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"
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" /> {{ template "svg/search2" (dict "Size" 15) }}
</span>
<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"
/>
</div>
</div>
<div class="lg:w-60">
{{ template "component/button" (dict
"Title" "Search"
"Variant" "Secondary"
)
}}
</div> </div>
</div>
<div class="lg:w-60">
{{ template "component/button" (dict
"Title" "Search"
"Variant" "Secondary"
) }}
</div>
</form>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{{ range $doc := .Data }}
{{ template "component/document-card" $doc }}
{{ end }}
</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>
{{ 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>
{{ end }}
</div>
<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"
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>
</form> </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">
Cancel Upload
</div>
</label>
</div> </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" <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
for="upload-file-button">{{ template "svg/upload" (dict "Size" 34) }}</label> {{ range $doc := .Data }}
</div> {{ template "component/document-card" $doc }}
{{ end }}
</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
>
{{ 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
>
{{ end }}
</div>
<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"
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>
</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"
>
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
>
</div>
{{ end }} {{ end }}

View File

@ -1,30 +1,53 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" <meta
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" /> 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-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" <meta
content="black-translucent" /> name="apple-mobile-web-app-status-bar-style"
<meta name="theme-color" content="black-translucent"
content="#F3F4F6" />
media="(prefers-color-scheme: light)" /> <meta
<meta name="theme-color" name="theme-color"
content="#1F2937" content="#F3F4F6"
media="(prefers-color-scheme: dark)" /> media="(prefers-color-scheme: light)"
/>
<meta
name="theme-color"
content="#1F2937"
media="(prefers-color-scheme: dark)"
/>
<title>AnthoLume - Error</title> <title>AnthoLume - Error</title>
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<link rel="stylesheet" href="/assets/style.css" /> <link rel="stylesheet" href="/assets/style.css" />
</head> </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="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"> <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> <h1
<p class="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">{{ .Error }}</p> class="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-gray-600 dark:text-gray-500"
<p class="mb-8 text-lg font-light text-gray-500 dark:text-gray-400">{{ .Message }}</p> >
<a href="/" {{ .Status }}
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>
<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>
</div> </div>
</body> </body>

View File

@ -2,83 +2,108 @@
{{ define "title" }}Home{{ end }} {{ define "title" }}Home{{ end }}
{{ define "header" }}<a href="./">Home</a>{{ end }} {{ define "header" }}<a href="./">Home</a>{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="w-full"> <div class="w-full">
<div class="relative w-full bg-white shadow-lg dark:bg-gray-700 rounded"> <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
Daily Read Totals 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> >
{{ $data := (getSVGGraphData .Data.GraphData 800 70 )}} Daily Read Totals
<div class="relative"> </p>
<svg viewBox="26 0 755 {{ $data.Height }}" {{ $data := (getSVGGraphData .Data.GraphData 800 70 ) }}
preserveAspectRatio="none" <div class="relative">
width="100%" <svg
height="6em"> viewBox="26 0 755 {{ $data.Height }}"
<!-- Bezier Line Graph --> preserveAspectRatio="none"
<path fill="#316BBE" fill-opacity="0.5" stroke="none" d="{{ $data.BezierPath }} {{ $data.BezierFill }}" /> width="100%"
<path fill="none" stroke="#316BBE" d="{{ $data.BezierPath }}" /> height="6em"
</svg> >
<div class="flex absolute w-full h-full top-0" <!-- Bezier Line Graph -->
style="width: calc(100%*31/30); <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"
style="width: calc(100%*31/30);
transform: translateX(-50%); transform: translateX(-50%);
left: 50%"> left: 50%"
{{ range $index, $item := $data.LinePoints }} >
<!-- Required for iOS "Hover" Events (onclick) --> {{ range $index, $item := $data.LinePoints }}
<div onclick <!-- Required for iOS "Hover" Events (onclick) -->
class="opacity-0 hover:opacity-100 w-full" <div
style="background: linear-gradient(rgba(128, 128, 128, 0.5), rgba(128, 128, 128, 0.5)) no-repeat center/2px 100%"> onclick
<div class="flex flex-col items-center p-2 rounded absolute top-3 dark:text-white text-xs pointer-events-none" class="opacity-0 hover:opacity-100 w-full"
style="transform: translateX(-50%); 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); 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).Date }}</span>
</div> <span
>{{ (index $.Data.GraphData $index).MinutesRead }}
minutes</span
>
</div>
</div>
{{ end }}
</div> </div>
{{ end }}
</div> </div>
</div> </div>
</div> </div>
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
{{ template "component/info-card" (dict
"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 }}
{{ template "component/streak-card" $item }}
{{ end }}
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{{ 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> </div>
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
{{ template "component/info-card" (dict
"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 }}
{{ template "component/streak-card" $item }}
{{ end }}
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{{ 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 }} {{ end }}

View File

@ -1,19 +1,29 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" <meta
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" /> 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-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" <meta
content="black-translucent" /> name="apple-mobile-web-app-status-bar-style"
<meta name="theme-color" content="black-translucent"
content="#F3F4F6" />
media="(prefers-color-scheme: light)" /> <meta
<meta name="theme-color" name="theme-color"
content="#1F2937" content="#F3F4F6"
media="(prefers-color-scheme: dark)" /> media="(prefers-color-scheme: light)"
<title>AnthoLume - {{ if .Register }}Register{{ else }}Login{{ end }}</title> />
<meta
name="theme-color"
content="#1F2937"
media="(prefers-color-scheme: dark)"
/>
<title>
AnthoLume - {{ if .Register }}Register{{ else }}Login{{ end }}
</title>
<link rel="manifest" href="./manifest.json" /> <link rel="manifest" href="./manifest.json" />
<link rel="stylesheet" href="./assets/style.css" /> <link rel="stylesheet" href="./assets/style.css" />
<!-- Service Worker / Offline Cache Flush --> <!-- Service Worker / Offline Cache Flush -->
@ -32,7 +42,8 @@
html { html {
height: calc(100% + env(safe-area-inset-bottom)); 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 */ /* No Scrollbar - IE, Edge, Firefox */
@ -50,77 +61,112 @@
<body class="bg-gray-100 dark:bg-gray-800 dark:text-white"> <body class="bg-gray-100 dark:bg-gray-800 dark:text-white">
<div class="flex flex-wrap w-full"> <div class="flex flex-wrap w-full">
<div class="flex flex-col w-full md:w-1/2"> <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> <p class="text-3xl text-center">Welcome.</p>
<form <form
class="flex flex-col pt-3 md:pt-8" class="flex flex-col pt-3 md:pt-8"
{{if {{ if
.Register}}action="./register" .Register
{{ else }}action="./login" }}
action="./register"
{{ else }}
action="./login"
{{ end }} {{ end }}
method="POST" method="POST"
> >
<div class="flex flex-col pt-4"> <div class="flex flex-col pt-4">
<div class="flex relative"> <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) }} {{ template "svg/user" (dict "Size" 15) }}
</span> </span>
<input type="text" <input
id="username" type="text"
name="username" id="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" name="username"
placeholder="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"
/>
</div> </div>
</div> </div>
<div class="flex flex-col pt-4 mb-12"> <div class="flex flex-col pt-4 mb-12">
<div class="flex relative"> <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) }} {{ template "svg/password" (dict "Size" 15) }}
</span> </span>
<input type="password" <input
id="password" type="password"
name="password" id="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" name="password"
placeholder="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"
<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>
</div> </div>
<button type="submit" <button
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"> 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 }} {{ if .Register }}
<span class="w-full">Register</span> <span class="w-full">Register</span>
{{ else }} {{ else }}
<span class="w-full">Submit</span> <span class="w-full">Submit</span>
{{ end }} {{ end }}
</button> </button>
</form> </form>
<div class="pt-12 pb-12 text-center"> <div class="pt-12 pb-12 text-center">
{{ if .Config.RegistrationEnabled }} {{ if .Register }} {{ if .Config.RegistrationEnabled }}
<p> {{ if .Register }}
Trying to login? <p>
<a href="./login" class="font-semibold underline">Login here.</a> Trying to login?
</p> <a href="./login" class="font-semibold underline"
{{ else }} >Login here.</a
<p> >
Don&#x27;t have an account? </p>
<a href="./register" class="font-semibold underline">Register here.</a> {{ else }}
</p> <p>
{{ end }} {{ end }} Don&#x27;t have an account?
<a href="./register" class="font-semibold underline"
>Register here.</a
>
</p>
{{ end }}
{{ end }}
<p class="mt-4"> <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> </p>
</div> </div>
</div> </div>
</div> </div>
<div class="hidden image-fader w-1/2 shadow-2xl h-screen relative md:block"> <div
<img class="w-full h-screen object-cover ease-in-out top-0 left-0" class="hidden image-fader w-1/2 shadow-2xl h-screen relative md:block"
src="/assets/images/book1.jpg" /> >
<img class="w-full h-screen object-cover ease-in-out top-0 left-0" <img
src="/assets/images/book2.jpg" /> class="w-full h-screen object-cover ease-in-out top-0 left-0"
<img class="w-full h-screen object-cover ease-in-out top-0 left-0" src="/assets/images/book1.jpg"
src="/assets/images/book3.jpg" /> />
<img class="w-full h-screen object-cover ease-in-out top-0 left-0" <img
src="/assets/images/book4.jpg" /> 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>
</div> </div>
<style> <style>

View File

@ -2,24 +2,27 @@
{{ define "title" }}Progress{{ end }} {{ define "title" }}Progress{{ end }}
{{ define "header" }}<a href="./progress">Progress</a>{{ end }} {{ define "header" }}<a href="./progress">Progress</a>{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<div class="inline-block min-w-full overflow-hidden rounded shadow"> <div class="inline-block min-w-full overflow-hidden rounded shadow">
<!-- Table Component - Utilizes Template "table-cell" --> <!-- Table Component - Utilizes Template "table-cell" -->
{{ template "component/table" (dict {{ template "component/table" (dict
"Columns" (slice "Document" "Device Name" "Percentage" "Created At") "Columns" (slice "Document" "Device Name" "Percentage" "Created At")
"Keys" (slice "Document" "DeviceName" "Percentage" "CreatedAt") "Keys" (slice "Document" "DeviceName" "Percentage" "CreatedAt")
"Rows" .Data "Rows" .Data
)}} )
}}
</div>
</div> </div>
</div>
{{ end }} {{ end }}
<!-- Table Cell Definition --> <!-- Table Cell Definition -->
{{ define "table-cell" }} {{ define "table-cell" }}
{{ if eq .Name "Document" }} {{ if eq .Name "Document" }}
<a href="./documents/{{ .Data.DocumentID }}">{{ .Data.Author }} - {{ .Data.Title }}</a> <a href="./documents/{{ .Data.DocumentID }}"
{{ else if eq .Name "Percentage" }} >{{ .Data.Author }} - {{ .Data.Title }}</a
{{ index (fields .Data) .Name }}% >
{{ else }} {{ else if eq .Name "Percentage" }}
{{ index (fields .Data) .Name }} {{ index (fields .Data) .Name }}%
{{ end }} {{ else }}
{{ index (fields .Data) .Name }}
{{ end }}
{{ end }} {{ end }}

View File

@ -2,110 +2,156 @@
{{ define "title" }}Search{{ end }} {{ define "title" }}Search{{ end }}
{{ define "header" }}<a href="./search">Search</a>{{ end }} {{ define "header" }}<a href="./search">Search</a>{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="w-full flex flex-col md:flex-row gap-4"> <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-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
<form class="flex gap-4 flex-col lg:flex-row" action="./search"> 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 w-full grow"> >
<div class="flex relative"> <form class="flex gap-4 flex-col lg:flex-row" action="./search">
<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"> <div class="flex flex-col w-full grow">
{{ template "svg/search2" (dict "Size" 15) }} <div class="flex relative">
</span> <span
<input type="text" 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"
id="query" >
name="query" {{ template "svg/search2" (dict "Size" 15) }}
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" </span>
placeholder="Query" /> <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"
/>
</div>
</div> </div>
</div> <div class="flex relative min-w-[12em]">
<div class="flex relative min-w-[12em]"> <span
<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"> 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> {{ template "svg/documents" (dict "Size" 15) }}
<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" </span>
id="source" <select
name="source"> 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"
<option value="Annas Archive">Annas Archive</option> id="source"
<option value="LibGen Fiction">LibGen Fiction</option> name="source"
<option value="LibGen Non-fiction">LibGen Non-fiction</option> >
</select> <option value="Annas Archive">Annas Archive</option>
</div> <option value="LibGen Fiction">LibGen Fiction</option>
<div class="lg:w-60"> <option value="LibGen Non-fiction">LibGen Non-fiction</option>
{{ template "component/button" (dict </select>
"Title" "Search" </div>
"Variant" "Secondary" <div class="lg:w-60">
) }} {{ template "component/button" (dict
</div> "Title" "Search"
</form> "Variant" "Secondary"
{{ if .SearchErrorMessage }} )
<span class="text-red-400 text-xs">{{ .SearchErrorMessage }}</span> }}
{{ end }} </div>
</div> </form>
<div class="inline-block min-w-full overflow-hidden rounded shadow"> {{ if .SearchErrorMessage }}
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm md:text-sm"> <span class="text-red-400 text-xs">{{ .SearchErrorMessage }}</span>
<thead class="text-gray-800 dark:text-gray-400"> {{ end }}
<tr> </div>
<th scope="col" <div class="inline-block min-w-full overflow-hidden rounded shadow">
class="w-12 p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"></th> <table
<th scope="col" class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm md:text-sm"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th> >
<th scope="col" <thead class="text-gray-800 dark:text-gray-400">
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Series</th> <tr>
<th scope="col" <th
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Type</th> scope="col"
<th scope="col" class="w-12 p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Size</th> ></th>
<th scope="col" <th
class="p-3 hidden md:block font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"> scope="col"
Date class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
</th> >
</tr> Document
</thead> </th>
<tbody class="text-black dark:text-white"> <th
{{ if not .Data }} scope="col"
<tr> class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
<td class="text-center p-3" colspan="6">No Results</td> >
</tr> Series
{{ end }} {{ range $item := .Data }} </th>
<tr> <th
<td class="p-3 border-b border-gray-200 text-gray-500 dark:text-gray-500"> scope="col"
<form action="./search" method="POST"> class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
<input class="hidden" >
type="text" Type
id="source" </th>
name="source" <th
value="{{ $.Source }}" /> scope="col"
<input class="hidden" class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
type="text" >
id="title" Size
name="title" </th>
value="{{ $item.Title }}" /> <th
<input class="hidden" scope="col"
type="text" class="p-3 hidden md:block font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
id="author" >
name="author" Date
value="{{ $item.Author }}" /> </th>
<button name="id" value="{{ $item.ID }}">{{ template "svg/download" }}</button> </tr>
</form> </thead>
</td> <tbody class="text-black dark:text-white">
<td class="p-3 border-b border-gray-200">{{ $item.Author }} - {{ $item.Title }}</td> {{ if not .Data }}
<td class="p-3 border-b border-gray-200"> <tr>
<p>{{ or $item.Series "N/A" }}</p> <td class="text-center p-3" colspan="6">No Results</td>
</td> </tr>
<td class="p-3 border-b border-gray-200"> {{ end }}
<p>{{ or $item.FileType "N/A" }}</p> {{ range $item := .Data }}
</td> <tr>
<td class="p-3 border-b border-gray-200"> <td
<p>{{ or $item.FileSize "N/A" }}</p> class="p-3 border-b border-gray-200 text-gray-500 dark:text-gray-500"
</td> >
<td class="hidden md:table-cell p-3 border-b border-gray-200"> <form action="./search" method="POST">
<p>{{ or $item.UploadDate "N/A" }}</p> <input
</td> class="hidden"
</tr> type="text"
{{ end }} id="source"
</tbody> name="source"
</table> value="{{ $.Source }}"
/>
<input
class="hidden"
type="text"
id="title"
name="title"
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>
</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">
<p>{{ or $item.Series "N/A" }}</p>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ or $item.FileType "N/A" }}</p>
</td>
<td class="p-3 border-b border-gray-200">
<p>{{ or $item.FileSize "N/A" }}</p>
</td>
<td class="hidden md:table-cell p-3 border-b border-gray-200">
<p>{{ or $item.UploadDate "N/A" }}</p>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div> </div>
</div> </div>
</div>
{{ end }} {{ end }}

View File

@ -2,127 +2,166 @@
{{ define "title" }}Settings{{ end }} {{ define "title" }}Settings{{ end }}
{{ define "header" }}<a href="./settings">Settings</a>{{ end }} {{ define "header" }}<a href="./settings">Settings</a>{{ end }}
{{ define "content" }} {{ define "content" }}
<div class="w-full flex flex-col md:flex-row gap-4"> <div class="w-full flex flex-col md:flex-row gap-4">
<div> <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
{{ template "svg/user" (dict "Size" 60) }} 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"
<p class="text-lg">{{ .Authorization.UserName }}</p> >
{{ template "svg/user" (dict "Size" 60) }}
<p class="text-lg">{{ .Authorization.UserName }}</p>
</div>
</div> </div>
</div> <div class="flex flex-col gap-4 grow">
<div class="flex flex-col gap-4 grow"> <div
<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"> 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" <p class="text-lg font-semibold mb-2">Change Password</p>
action="./settings" <form
method="POST"> class="flex gap-4 flex-col lg:flex-row"
<div class="flex flex-col grow"> action="./settings"
<div class="flex relative"> method="POST"
<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) }} <div class="flex flex-col grow">
</span> <div class="flex relative">
<input type="password" <span
id="password" 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"
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" {{ template "svg/password" (dict "Size" 15) }}
placeholder="Password" /> </span>
<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"
/>
</div>
</div> </div>
</div> <div class="flex flex-col grow">
<div class="flex flex-col grow"> <div class="flex relative">
<div class="flex relative"> <span
<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"> 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> {{ template "svg/password" (dict "Size" 15) }}
<input type="password" </span>
id="new_password" <input
name="new_password" type="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" id="new_password"
placeholder="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"
/>
</div>
</div> </div>
</div> <div class="lg:w-60">
<div class="lg:w-60"> {{ template "component/button" (dict
{{ template "component/button" (dict "Title" "Submit"
"Title" "Submit" "Variant" "Secondary"
"Variant" "Secondary" )
) }} }}
</div> </div>
</form> </form>
{{ if .PasswordErrorMessage }} {{ if .PasswordErrorMessage }}
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span> <span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
{{ else if .PasswordMessage }} {{ else if .PasswordMessage }}
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span> <span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
{{ end }} {{ end }}
</div> </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
<p class="text-lg font-semibold mb-2">Change Timezone</p> class="flex flex-col grow gap-2 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="./settings" <p class="text-lg font-semibold mb-2">Change Timezone</p>
method="POST"> <form
<div class="flex relative grow"> class="flex gap-4 flex-col lg:flex-row"
<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"> action="./settings"
{{ template "svg/clock" (dict "Size" 15) }} method="POST"
</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" <div class="flex relative grow">
id="timezone" <span
name="timezone"> 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"
{{ range $item := getTimeZones }} >
<option {{ if (eq $item $.Data.Timezone) }}selected{{ end }} value="{{ $item }}"> {{ template "svg/clock" (dict "Size" 15) }}
{{ $item }} </span>
</option> <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"
>
{{ range $item := getTimeZones }}
<option
{{ if (eq $item $.Data.Timezone) }}selected{{ end }}
value="{{ $item }}"
>
{{ $item }}
</option>
{{ end }}
</select>
</div>
<div class="lg:w-60">
{{ template "component/button" (dict
"Title" "Submit"
"Variant" "Secondary"
)
}}
</div>
</form>
{{ if .TimeOffsetErrorMessage }}
<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"
>
<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"
>
Name
</th>
<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>
</tr>
</thead>
<tbody class="text-black dark:text-white">
{{ if not .Data.Devices }}
<tr>
<td class="text-center p-3" colspan="3">No Results</td>
</tr>
{{ end }} {{ end }}
</select> {{ range $device := .Data.Devices }}
</div> <tr>
<div class="lg:w-60"> <td class="p-3 pl-0">
{{ template "component/button" (dict <p>{{ $device.DeviceName }}</p>
"Title" "Submit" </td>
"Variant" "Secondary" <td class="p-3">
) }} <p>{{ $device.LastSynced }}</p>
</div> </td>
</form> <td class="p-3">
{{ if .TimeOffsetErrorMessage }} <p>{{ $device.CreatedAt }}</p>
<span class="text-red-400 text-xs">{{ .TimeOffsetErrorMessage }}</span> </td>
{{ else if .TimeOffsetMessage }} </tr>
<span class="text-green-400 text-xs">{{ .TimeOffsetMessage }}</span> {{ end }}
{{ end }} </tbody>
</div> </table>
<div class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"> </div>
<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">
Name
</th>
<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>
</tr>
</thead>
<tbody class="text-black dark:text-white">
{{ if not .Data.Devices }}
<tr>
<td class="text-center p-3" colspan="3">No Results</td>
</tr>
{{ end }}
{{ range $device := .Data.Devices }}
<tr>
<td class="p-3 pl-0">
<p>{{ $device.DeviceName }}</p>
</td>
<td class="p-3">
<p>{{ $device.LastSynced }}</p>
</td>
<td class="p-3">
<p>{{ $device.CreatedAt }}</p>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div> </div>
</div> </div>
</div>
{{ end }} {{ end }}