chore(formatting): djlint templates
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Activity{{end}} {{define "header"}}
|
||||
<a href="./activity">Activity</a>
|
||||
{{end}} {{define "content"}}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Document
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Time
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Duration
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Percent
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="4">No Results</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{range $activity := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<a href="./documents/{{ $activity.DocumentID }}">{{ $activity.Author }} - {{ $activity.Title }}</p></a>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $activity.StartTime }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $activity.Duration }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $activity.EndPercentage }}%</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
44
templates/pages/activity.tmpl
Normal file
44
templates/pages/activity.tmpl
Normal file
@@ -0,0 +1,44 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Activity{{ end }}
|
||||
{{ define "header" }}<a href="./activity">Activity</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Time</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Duration</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Percent</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="4">No Results</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ range $activity := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<a href="./documents/{{ $activity.DocumentID }}">{{ $activity.Author }} - {{ $activity.Title }}
|
||||
</p>
|
||||
</a>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $activity.StartTime }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $activity.Duration }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $activity.EndPercentage }}%</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,15 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Admin - Logs{{end}} {{define
|
||||
"header"}}
|
||||
<a class="whitespace-pre" href="../admin">Admin - Logs</a>
|
||||
{{end}} {{define "content"}}
|
||||
|
||||
<div
|
||||
class="flex flex-col-reverse text-black dark:text-white"
|
||||
style="font-family: monospace"
|
||||
>
|
||||
{{range $log := .Data }}
|
||||
<span class="whitespace-pre">{{ $log }}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{end}}
|
||||
11
templates/pages/admin-logs.tmpl
Normal file
11
templates/pages/admin-logs.tmpl
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Admin - Logs{{ end }}
|
||||
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Logs</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="flex flex-col-reverse text-black dark:text-white"
|
||||
style="font-family: monospace">
|
||||
{{ range $log := .Data }}
|
||||
<span class="whitespace-pre">{{ $log }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,50 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Admin - Users{{end}} {{define "header"}}
|
||||
<a class="whitespace-pre" href="../admin">Admin - Users</a>
|
||||
{{end}} {{define "content"}}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800 w-12">
|
||||
{{ template "svg/add" }}
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
User
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800 text-center">
|
||||
Permissions
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800 w-48">
|
||||
Created
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="2">No Results</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{range $user := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400">
|
||||
{{ template "svg/delete" }}
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $user.ID }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200 text-center min-w-40">
|
||||
<span class="px-2 py-1 rounded-md text-white dark:text-black {{if $user.Admin}}bg-gray-800 dark:bg-gray-100{{else}}bg-gray-400 dark:bg-gray-600 cursor-pointer{{end}}">admin</span>
|
||||
<span class="px-2 py-1 rounded-md text-white dark:text-black {{if $user.Admin}}bg-gray-400 dark:bg-gray-600 cursor-pointer{{else}}bg-gray-800 dark:bg-gray-100{{end}}">user</span>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $user.CreatedAt }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
45
templates/pages/admin-users.tmpl
Normal file
45
templates/pages/admin-users.tmpl
Normal file
@@ -0,0 +1,45 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Admin - Users{{ end }}
|
||||
{{ define "header" }}<a class="whitespace-pre" href="../admin">Admin - Users</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800 w-12">
|
||||
{{ template "svg/add" }}
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">User</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800 text-center">
|
||||
Permissions
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800 w-48">Created</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="2">No Results</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ range $user := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200 text-gray-800 dark:text-gray-400">{{ template "svg/delete" }}</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $user.ID }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200 text-center min-w-40">
|
||||
<span class="px-2 py-1 rounded-md text-white dark:text-black {{ if $user.Admin }}bg-gray-800 dark:bg-gray-100{{ else }}bg-gray-400 dark:bg-gray-600 cursor-pointer{{ end }}">admin</span>
|
||||
<span class="px-2 py-1 rounded-md text-white dark:text-black {{ if $user.Admin }}bg-gray-400 dark:bg-gray-600 cursor-pointer{{ else }}bg-gray-800 dark:bg-gray-100{{ end }}">user</span>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $user.CreatedAt }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,190 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Admin - General{{end}} {{define
|
||||
"header"}}
|
||||
<a class="whitespace-pre" href="./admin">Admin - General</a>
|
||||
{{end}} {{define "content"}}
|
||||
<div class="w-full flex flex-col md:flex-row gap-4">
|
||||
<div>
|
||||
<div
|
||||
class="flex flex-col p-4 items-center rounded shadow-lg md:w-60 lg:w-80 bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
{{ template "svg/user" (dict "Size" 60) }}
|
||||
<p class="text-lg">{{ .Authorization.UserName }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<div
|
||||
class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
<p class="text-lg font-semibold mb-2">Import Documents</p>
|
||||
<form class="flex gap-4 flex-col" action="./admin" method="POST">
|
||||
<input type="text" name="action" value="IMPORT" class="hidden" />
|
||||
<div class="flex gap-4">
|
||||
<div class="flex grow 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"
|
||||
>
|
||||
{{ template "svg/import" (dict "Size" 15) }}
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
name="import_directory"
|
||||
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="Directory"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col mr-4">
|
||||
<div class="inline-flex gap-2">
|
||||
<input
|
||||
checked
|
||||
type="radio"
|
||||
id="copy"
|
||||
name="import_type"
|
||||
value="COPY"
|
||||
/>
|
||||
<label for="copy"> Copy</label>
|
||||
</div>
|
||||
<div class="inline-flex gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
id="direct"
|
||||
name="import_type"
|
||||
value="DIRECT"
|
||||
/>
|
||||
<label for="direct"> Direct</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Import Directory</span>
|
||||
</button>
|
||||
</form>
|
||||
{{ if .PasswordErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
|
||||
{{ else if .PasswordMessage }}
|
||||
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
|
||||
{{ end }}
|
||||
</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"
|
||||
>
|
||||
<p class="text-lg font-semibold mb-2">Backup & Restore</p>
|
||||
<div class="flex flex-col gap-4">
|
||||
<form class="flex justify-between" action="./admin" method="POST">
|
||||
<input type="text" name="action" value="BACKUP" class="hidden" />
|
||||
<div class="flex gap-8 items-center">
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="backup_covers"
|
||||
name="backup_types"
|
||||
value="COVERS"
|
||||
/>
|
||||
<label for="backup_covers"> Covers</label>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="backup_documents"
|
||||
name="backup_types"
|
||||
value="DOCUMENTS"
|
||||
/>
|
||||
<label for="backup_documents"> Documents</label>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Backup</span>
|
||||
</button>
|
||||
</form>
|
||||
<form
|
||||
method="POST"
|
||||
enctype="multipart/form-data"
|
||||
action="./admin"
|
||||
class="flex justify-between grow"
|
||||
>
|
||||
<input type="text" name="action" value="RESTORE" class="hidden" />
|
||||
<div class="flex items-center w-1/2">
|
||||
<input
|
||||
type="file"
|
||||
accept=".zip"
|
||||
name="restore_file"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Restore</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{ if .PasswordErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
|
||||
{{ else if .PasswordMessage }}
|
||||
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
<p class="text-lg font-semibold">Tasks</p>
|
||||
<table class="min-w-full bg-white dark:bg-gray-700 text-sm">
|
||||
<tbody class="text-black dark:text-white">
|
||||
<tr>
|
||||
<td class="pl-0">
|
||||
<p>Metadata Matching</p>
|
||||
</td>
|
||||
<td class="py-2 float-right">
|
||||
<form action="./admin" method="POST">
|
||||
<input
|
||||
type="text"
|
||||
name="action"
|
||||
value="METADATA_MATCH"
|
||||
class="hidden"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Run</span>
|
||||
</button>
|
||||
</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"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Run</span>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
129
templates/pages/admin.tmpl
Normal file
129
templates/pages/admin.tmpl
Normal file
@@ -0,0 +1,129 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Admin - General{{ end }}
|
||||
{{ define "header" }}<a class="whitespace-pre" href="./admin">Admin - General</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="w-full flex flex-col md:flex-row gap-4">
|
||||
<div>
|
||||
<div class="flex flex-col p-4 items-center rounded shadow-lg md:w-60 lg:w-80 bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
{{ template "svg/user" (dict "Size" 60) }}
|
||||
<p class="text-lg">{{ .Authorization.UserName }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<div class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
<p class="text-lg font-semibold mb-2">Import Documents</p>
|
||||
<form class="flex gap-4 flex-col" action="./admin" method="POST">
|
||||
<input type="text" name="action" value="IMPORT" class="hidden" />
|
||||
<div class="flex gap-4">
|
||||
<div class="flex grow 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">
|
||||
{{ template "svg/import" (dict "Size" 15) }}
|
||||
</span>
|
||||
<input type="text"
|
||||
name="import_directory"
|
||||
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="Directory" />
|
||||
</div>
|
||||
<div class="flex flex-col mr-4">
|
||||
<div class="inline-flex gap-2">
|
||||
<input checked type="radio" id="copy" name="import_type" value="COPY" />
|
||||
<label for="copy">Copy</label>
|
||||
</div>
|
||||
<div class="inline-flex gap-2">
|
||||
<input type="radio" id="direct" name="import_type" value="DIRECT" />
|
||||
<label for="direct">Direct</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Import Directory</span>
|
||||
</button>
|
||||
</form>
|
||||
{{ if .PasswordErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
|
||||
{{ else if .PasswordMessage }}
|
||||
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
|
||||
{{ end }}
|
||||
</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">
|
||||
<p class="text-lg font-semibold mb-2">Backup & Restore</p>
|
||||
<div class="flex flex-col gap-4">
|
||||
<form class="flex justify-between" action="./admin" method="POST">
|
||||
<input type="text" name="action" value="BACKUP" class="hidden" />
|
||||
<div class="flex gap-8 items-center">
|
||||
<div>
|
||||
<input type="checkbox" id="backup_covers" name="backup_types" value="COVERS" />
|
||||
<label for="backup_covers">Covers</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox"
|
||||
id="backup_documents"
|
||||
name="backup_types"
|
||||
value="DOCUMENTS" />
|
||||
<label for="backup_documents">Documents</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Backup</span>
|
||||
</button>
|
||||
</form>
|
||||
<form method="POST"
|
||||
enctype="multipart/form-data"
|
||||
action="./admin"
|
||||
class="flex justify-between grow">
|
||||
<input type="text" name="action" value="RESTORE" class="hidden" />
|
||||
<div class="flex items-center w-1/2">
|
||||
<input type="file" accept=".zip" name="restore_file" class="w-full" />
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Restore</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{{ if .PasswordErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
|
||||
{{ else if .PasswordMessage }}
|
||||
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="flex flex-col grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
<p class="text-lg font-semibold">Tasks</p>
|
||||
<table class="min-w-full bg-white dark:bg-gray-700 text-sm">
|
||||
<tbody class="text-black dark:text-white">
|
||||
<tr>
|
||||
<td class="pl-0">
|
||||
<p>Metadata Matching</p>
|
||||
</td>
|
||||
<td class="py-2 float-right">
|
||||
<form action="./admin" method="POST">
|
||||
<input type="text" name="action" value="METADATA_MATCH" class="hidden" />
|
||||
<button type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Run</span>
|
||||
</button>
|
||||
</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" />
|
||||
<button type="submit"
|
||||
class="w-40 px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Run</span>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,382 +0,0 @@
|
||||
{{template "base" . }}
|
||||
|
||||
{{define "title"}}Documents{{end}}
|
||||
|
||||
{{define "header"}}
|
||||
<a href="/documents">Documents</a>
|
||||
{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="h-full w-full relative">
|
||||
<!-- Document Info -->
|
||||
<div class="h-full w-full overflow-scroll bg-white shadow-lg dark:bg-gray-700 rounded dark:text-white p-4">
|
||||
<div class="flex flex-col gap-2 float-left w-44 md:w-60 lg:w-80 mr-4 mb-2 relative">
|
||||
<label class="z-10 cursor-pointer" for="edit-cover-button">
|
||||
<img class="rounded object-fill w-full" src="/documents/{{.Data.ID}}/cover"></img>
|
||||
</label>
|
||||
|
||||
{{ if .Data.Filepath }}
|
||||
<a
|
||||
href="/reader#id={{ .Data.ID }}&type=REMOTE"
|
||||
class="z-10 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded text-sm text-center py-1 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800"
|
||||
>Read</a>
|
||||
{{ end }}
|
||||
|
||||
<div class="flex flex-wrap-reverse justify-between z-20 gap-2 relative">
|
||||
<div class="min-w-[50%] md:mr-2">
|
||||
<div class="flex gap-1 text-sm">
|
||||
<p class="text-gray-500">ISBN-10:</p>
|
||||
<p class="font-medium">
|
||||
{{ or .Data.Isbn10 "N/A" }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-1 text-sm">
|
||||
<p class="text-gray-500">ISBN-13:</p>
|
||||
<p class="font-medium">
|
||||
{{ or .Data.Isbn13 "N/A" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex grow justify-between my-auto text-gray-500 dark:text-gray-500">
|
||||
<input type="checkbox" id="edit-cover-button" class="hidden css-button"/>
|
||||
<div class="absolute z-30 flex flex-col gap-2 top-0 left-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
|
||||
<form
|
||||
method="POST"
|
||||
enctype="multipart/form-data"
|
||||
action="./{{ .Data.ID }}/edit"
|
||||
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm"
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
id="cover_file"
|
||||
name="cover_file"
|
||||
>
|
||||
<button
|
||||
class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Upload Cover</button>
|
||||
</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" />
|
||||
<button
|
||||
class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Remove Cover</button>
|
||||
</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"
|
||||
>
|
||||
<button
|
||||
class="font-medium w-24 px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Delete</button>
|
||||
</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"
|
||||
>
|
||||
<button
|
||||
class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Identify</button>
|
||||
</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>
|
||||
</div>
|
||||
<div class="grid sm:grid-cols-2 justify-between gap-4 pb-4">
|
||||
<div class="relative">
|
||||
<div class="text-gray-500 inline-flex gap-2 relative">
|
||||
<p>Title</p>
|
||||
<label class="my-auto" for="edit-title-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
|
||||
<input type="checkbox" id="edit-title-button" class="hidden css-button"/>
|
||||
<div class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
|
||||
<form
|
||||
method="POST"
|
||||
action="./{{ .Data.ID }}/edit"
|
||||
class="flex flex-col gap-2 text-black dark:text-white text-sm"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="title"
|
||||
name="title"
|
||||
value="{{ or .Data.Title "N/A" }}"
|
||||
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
|
||||
>
|
||||
<button
|
||||
class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p class="font-medium text-lg">
|
||||
{{ or .Data.Title "N/A" }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<div class="text-gray-500 inline-flex gap-2 relative">
|
||||
<p>Author</p>
|
||||
<label class="my-auto" for="edit-author-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
|
||||
<input type="checkbox" id="edit-author-button" class="hidden css-button"/>
|
||||
|
||||
<div class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
|
||||
<form
|
||||
method="POST"
|
||||
action="./{{ .Data.ID }}/edit"
|
||||
class="flex flex-col gap-2 text-black dark:text-white text-sm"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="author"
|
||||
name="author"
|
||||
value="{{ or .Data.Author "N/A" }}"
|
||||
class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white"
|
||||
>
|
||||
<button
|
||||
class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p class="font-medium text-lg">
|
||||
{{ or .Data.Author "N/A" }}
|
||||
</p>
|
||||
</div>
|
||||
<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="text-gray-500 inline-flex gap-2 relative">
|
||||
<p>Description</p>
|
||||
<label class="my-auto" for="edit-description-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
|
||||
</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"></img>
|
||||
<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>
|
||||
<button
|
||||
class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Save</button>
|
||||
</form>
|
||||
</div>
|
||||
<p>{{ or .Data.Description "N/A" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ if .MetadataError }}
|
||||
<div class="absolute top-0 left-0 w-full h-full z-50">
|
||||
<div class="fixed top-0 left-0 bg-black opacity-50 w-screen h-screen"></div>
|
||||
<div class="relative flex flex-col gap-4 p-4 max-h-[95%] bg-white dark:bg-gray-800 overflow-scroll -translate-x-2/4 -translate-y-2/4 top-1/2 left-1/2 w-5/6 overflow-hidden shadow rounded">
|
||||
<div class="text-center">
|
||||
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">No Metadata Results Found</h3>
|
||||
</div>
|
||||
<a href="/documents/{{ .Data.ID }}"
|
||||
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"
|
||||
type="submit"
|
||||
>Back to Document</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!-- Metadata Info -->
|
||||
{{ 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/{{ .Data.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"></img>
|
||||
</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 gap-4 m-4">
|
||||
<a href="/documents/{{ .Data.ID }}"
|
||||
class="w-24 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"
|
||||
type="submit"
|
||||
>Cancel</a>
|
||||
<button
|
||||
form="metadata-save"
|
||||
class="w-24 font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit"
|
||||
>Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.css-button:checked + div {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.css-button + div {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
{{end}}
|
||||
299
templates/pages/document.tmpl
Normal file
299
templates/pages/document.tmpl
Normal file
@@ -0,0 +1,299 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Documents{{ end }}
|
||||
{{ define "header" }}<a href="/documents">Documents</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="h-full w-full relative">
|
||||
<!-- Document Info -->
|
||||
<div class="h-full w-full overflow-scroll bg-white shadow-lg dark:bg-gray-700 rounded dark:text-white p-4">
|
||||
<div class="flex flex-col gap-2 float-left w-44 md:w-60 lg:w-80 mr-4 mb-2 relative">
|
||||
<label class="z-10 cursor-pointer" for="edit-cover-button">
|
||||
<img class="rounded object-fill w-full"
|
||||
src="/documents/{{.Data.ID}}/cover" />
|
||||
</label>
|
||||
{{ if .Data.Filepath }}
|
||||
<a href="/reader#id={{ .Data.ID }}&type=REMOTE"
|
||||
class="z-10 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded text-sm text-center py-1 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Read</a>
|
||||
{{ end }}
|
||||
<div class="flex flex-wrap-reverse justify-between z-20 gap-2 relative">
|
||||
<div class="min-w-[50%] md:mr-2">
|
||||
<div class="flex gap-1 text-sm">
|
||||
<p class="text-gray-500">ISBN-10:</p>
|
||||
<p class="font-medium">{{ or .Data.Isbn10 "N/A" }}</p>
|
||||
</div>
|
||||
<div class="flex gap-1 text-sm">
|
||||
<p class="text-gray-500">ISBN-13:</p>
|
||||
<p class="font-medium">{{ or .Data.Isbn13 "N/A" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex grow justify-between my-auto text-gray-500 dark:text-gray-500">
|
||||
<input type="checkbox" id="edit-cover-button" class="hidden css-button" />
|
||||
<div class="absolute z-30 flex flex-col gap-2 top-0 left-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
|
||||
<form method="POST"
|
||||
enctype="multipart/form-data"
|
||||
action="./{{ .Data.ID }}/edit"
|
||||
class="flex flex-col gap-2 w-72 text-black dark:text-white text-sm">
|
||||
<input type="file" id="cover_file" name="cover_file">
|
||||
<button class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Upload Cover</button>
|
||||
</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" />
|
||||
<button class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Remove Cover</button>
|
||||
</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">
|
||||
<button class="font-medium w-24 px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Delete</button>
|
||||
</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">
|
||||
<button class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Identify</button>
|
||||
</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>
|
||||
</div>
|
||||
<div class="grid sm:grid-cols-2 justify-between gap-4 pb-4">
|
||||
<div class="relative">
|
||||
<div class="text-gray-500 inline-flex gap-2 relative">
|
||||
<p>Title</p>
|
||||
<label class="my-auto" for="edit-title-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
|
||||
<input type="checkbox" id="edit-title-button" class="hidden css-button" />
|
||||
<div class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
|
||||
<form method="POST"
|
||||
action="./{{ .Data.ID }}/edit"
|
||||
class="flex flex-col gap-2 text-black dark:text-white text-sm">
|
||||
<input type="text" id="title" name="title" value="{{ or .Data.Title "N/A" }}" class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white">
|
||||
<button class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p class="font-medium text-lg">{{ or .Data.Title "N/A" }}</p>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<div class="text-gray-500 inline-flex gap-2 relative">
|
||||
<p>Author</p>
|
||||
<label class="my-auto" for="edit-author-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
|
||||
<input type="checkbox" id="edit-author-button" class="hidden css-button" />
|
||||
<div class="absolute z-30 top-7 right-0 p-3 transition-all duration-200 bg-gray-200 rounded shadow-lg shadow-gray-500 dark:shadow-gray-900 dark:bg-gray-600">
|
||||
<form method="POST"
|
||||
action="./{{ .Data.ID }}/edit"
|
||||
class="flex flex-col gap-2 text-black dark:text-white text-sm">
|
||||
<input type="text" id="author" name="author" value="{{ or .Data.Author "N/A" }}" class="p-2 bg-gray-300 text-black dark:bg-gray-700 dark:text-white">
|
||||
<button class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<p class="font-medium text-lg">{{ or .Data.Author "N/A" }}</p>
|
||||
</div>
|
||||
<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="text-gray-500 inline-flex gap-2 relative">
|
||||
<p>Description</p>
|
||||
<label class="my-auto" for="edit-description-button">{{ template "svg/edit" (dict "Size" 18) }}</label>
|
||||
</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>
|
||||
<button class="font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
<p>{{ or .Data.Description "N/A" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{ if .MetadataError }}
|
||||
<div class="absolute top-0 left-0 w-full h-full z-50">
|
||||
<div class="fixed top-0 left-0 bg-black opacity-50 w-screen h-screen"></div>
|
||||
<div class="relative flex flex-col gap-4 p-4 max-h-[95%] bg-white dark:bg-gray-800 overflow-scroll -translate-x-2/4 -translate-y-2/4 top-1/2 left-1/2 w-5/6 overflow-hidden shadow rounded">
|
||||
<div class="text-center">
|
||||
<h3 class="text-lg font-bold leading-6 dark:text-gray-300">No Metadata Results Found</h3>
|
||||
</div>
|
||||
<a href="/documents/{{ .Data.ID }}"
|
||||
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"
|
||||
type="submit">Back to Document</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<!-- Metadata Info -->
|
||||
{{ 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/{{ .Data.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 gap-4 m-4">
|
||||
<a href="/documents/{{ .Data.ID }}"
|
||||
class="w-24 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"
|
||||
type="submit">Cancel</a>
|
||||
<button form="metadata-save"
|
||||
class="w-24 font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
type="submit">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<style>
|
||||
.css-button:checked+div {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.css-button+div {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
{{ end }}
|
||||
@@ -1,141 +0,0 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "title"}}Documents{{end}}
|
||||
|
||||
{{define "header"}}
|
||||
<a href="./documents">Documents</a>
|
||||
{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div
|
||||
class="flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
<form class="flex gap-4 flex-col lg:flex-row" action="./documents" method="GET">
|
||||
<div class="flex flex-col w-full grow">
|
||||
<div class="flex relative">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ 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>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Search</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{{range $doc := .Data }}
|
||||
<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="min-w-fit my-auto h-48 relative">
|
||||
<a href="./documents/{{$doc.ID}}">
|
||||
<img class="rounded object-cover h-full" src="./documents/{{$doc.ID}}/cover"></img>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Title</p>
|
||||
<p class="font-medium">
|
||||
{{ or $doc.Title "Unknown" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Author</p>
|
||||
<p class="font-medium">
|
||||
{{ or $doc.Author "Unknown" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Progress</p>
|
||||
<p class="font-medium">
|
||||
{{ $doc.Percentage }}%
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Time Read</p>
|
||||
<p class="font-medium">
|
||||
{{ niceSeconds $doc.TotalTimeSeconds }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute flex flex-col gap-2 right-4 bottom-4 text-gray-500 dark:text-gray-400">
|
||||
<a href="./activity?document={{ $doc.ID }}">{{ template "svg/activity" }}</a>
|
||||
|
||||
{{ if $doc.Filepath }}
|
||||
<a href="./documents/{{$doc.ID}}/file">{{ template "svg/download" }}</a>
|
||||
{{ else }}
|
||||
{{ template "svg/download" (dict "Disabled" true) }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{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="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>
|
||||
|
||||
<style>
|
||||
.css-button:checked + div {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.css-button + div {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.css-button:checked + div + label {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
{{end}}
|
||||
120
templates/pages/documents.tmpl
Normal file
120
templates/pages/documents.tmpl
Normal file
@@ -0,0 +1,120 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Documents{{ end }}
|
||||
{{ define "header" }}<a href="./documents">Documents</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="flex flex-col gap-2 grow p-4 mb-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
<form class="flex gap-4 flex-col lg:flex-row"
|
||||
action="./documents"
|
||||
method="GET">
|
||||
<div class="flex flex-col w-full grow">
|
||||
<div class="flex relative">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ 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>
|
||||
<button type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Search</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{{ range $doc := .Data }}
|
||||
<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="min-w-fit my-auto h-48 relative">
|
||||
<a href="./documents/{{$doc.ID}}">
|
||||
<img class="rounded object-cover h-full"
|
||||
src="./documents/{{$doc.ID}}/cover" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Title</p>
|
||||
<p class="font-medium">{{ or $doc.Title "Unknown" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Author</p>
|
||||
<p class="font-medium">{{ or $doc.Author "Unknown" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Progress</p>
|
||||
<p class="font-medium">{{ $doc.Percentage }}%</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline-flex shrink-0 items-center">
|
||||
<div>
|
||||
<p class="text-gray-400">Time Read</p>
|
||||
<p class="font-medium">{{ niceSeconds $doc.TotalTimeSeconds }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute flex flex-col gap-2 right-4 bottom-4 text-gray-500 dark:text-gray-400">
|
||||
<a href="./activity?document={{ $doc.ID }}">{{ template "svg/activity" }}</a>
|
||||
{{ if $doc.Filepath }}
|
||||
<a href="./documents/{{$doc.ID}}/file">{{ template "svg/download" }}</a>
|
||||
{{ else }}
|
||||
{{ template "svg/download" (dict "Disabled" true) }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ 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="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>
|
||||
<style>
|
||||
.css-button:checked+div {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.css-button+div {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.css-button:checked+div+label {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
{{ end }}
|
||||
@@ -1,56 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<meta
|
||||
name="theme-color"
|
||||
content="#F3F4F6"
|
||||
media="(prefers-color-scheme: light)"
|
||||
/>
|
||||
<meta
|
||||
name="theme-color"
|
||||
content="#1F2937"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
/>
|
||||
|
||||
<title>AnthoLume - Error</title>
|
||||
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="stylesheet" href="/assets/style.css" />
|
||||
</head>
|
||||
<body
|
||||
class="bg-gray-100 dark:bg-gray-800 flex flex-col justify-center h-screen"
|
||||
>
|
||||
<div class="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
|
||||
<div class="mx-auto max-w-screen-sm text-center">
|
||||
<h1
|
||||
class="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-gray-600 dark:text-gray-500"
|
||||
>
|
||||
{{ .Status }}
|
||||
</h1>
|
||||
<p
|
||||
class="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white"
|
||||
>
|
||||
{{ .Error }}
|
||||
</p>
|
||||
<p class="mb-8 text-lg font-light text-gray-500 dark:text-gray-400">
|
||||
{{ .Message }}
|
||||
</p>
|
||||
<a
|
||||
href="/"
|
||||
class="rounded text-center font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100"
|
||||
>Back to Homepage</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
31
templates/pages/error.tmpl
Normal file
31
templates/pages/error.tmpl
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent" />
|
||||
<meta name="theme-color"
|
||||
content="#F3F4F6"
|
||||
media="(prefers-color-scheme: light)" />
|
||||
<meta name="theme-color"
|
||||
content="#1F2937"
|
||||
media="(prefers-color-scheme: dark)" />
|
||||
<title>AnthoLume - Error</title>
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="stylesheet" href="/assets/style.css" />
|
||||
</head>
|
||||
<body class="bg-gray-100 dark:bg-gray-800 flex flex-col justify-center h-screen">
|
||||
<div class="py-8 px-4 mx-auto max-w-screen-xl lg:py-16 lg:px-6">
|
||||
<div class="mx-auto max-w-screen-sm text-center">
|
||||
<h1 class="mb-4 text-7xl tracking-tight font-extrabold lg:text-9xl text-gray-600 dark:text-gray-500">{{ .Status }}</h1>
|
||||
<p class="mb-4 text-3xl tracking-tight font-bold text-gray-900 md:text-4xl dark:text-white">{{ .Error }}</p>
|
||||
<p class="mb-8 text-lg font-light text-gray-500 dark:text-gray-400">{{ .Message }}</p>
|
||||
<a href="/"
|
||||
class="rounded text-center font-medium px-2 py-1 text-white bg-gray-500 dark:text-gray-800 hover:bg-gray-800 dark:hover:bg-gray-100">Back to Homepage</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,243 +0,0 @@
|
||||
{{template "base" .}}
|
||||
{{define "title"}}Home{{end}}
|
||||
{{define "header"}}<a href="./">Home</a>{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="relative w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded"
|
||||
>
|
||||
<p
|
||||
class="absolute top-3 text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500"
|
||||
>
|
||||
Daily Read Totals
|
||||
</p>
|
||||
|
||||
{{ $data := (getSVGGraphData .Data.GraphData 800 70 )}}
|
||||
<svg
|
||||
viewBox="26 0 755 {{ $data.Height }}"
|
||||
preserveAspectRatio="none"
|
||||
width="100%"
|
||||
height="4em"
|
||||
>
|
||||
<!-- Bezier Line Graph -->
|
||||
<path
|
||||
fill="#316BBE"
|
||||
fill-opacity="0.5"
|
||||
stroke="none"
|
||||
d="{{ $data.BezierPath }} {{ $data.BezierFill }}"
|
||||
/>
|
||||
|
||||
<path fill="none" stroke="#316BBE" d="{{ $data.BezierPath }}" />
|
||||
|
||||
{{ range $index, $item := $data.LinePoints }}
|
||||
<line
|
||||
class="hover-trigger"
|
||||
stroke="black"
|
||||
stroke-opacity="0.0"
|
||||
stroke-width="{{ $data.Offset }}"
|
||||
x1="{{ $item.X }}"
|
||||
x2="{{ $item.X }}"
|
||||
y1="0"
|
||||
y2="{{ $data.Height }}"
|
||||
></line>
|
||||
<g class="hover-item">
|
||||
<line
|
||||
class="text-black dark:text-white"
|
||||
stroke-opacity="0.2"
|
||||
x1="{{ $item.X }}"
|
||||
x2="{{ $item.X }}"
|
||||
y1="30"
|
||||
y2="{{ $data.Height }}"
|
||||
></line>
|
||||
<text
|
||||
class="text-black dark:text-white"
|
||||
alignment-baseline="middle"
|
||||
transform="translate({{ $item.X }}, 5) translate(-30, 8)"
|
||||
font-size="10"
|
||||
>
|
||||
{{ (index $.Data.GraphData $index).Date }}
|
||||
</text>
|
||||
<text
|
||||
class="text-black dark:text-white"
|
||||
alignment-baseline="middle"
|
||||
transform="translate({{ $item.X }}, 25) translate(-30, -2)"
|
||||
font-size="10"
|
||||
>
|
||||
{{ (index $.Data.GraphData $index).MinutesRead }} minutes
|
||||
</text>
|
||||
</g>
|
||||
{{ end }}
|
||||
</svg>
|
||||
|
||||
<style>
|
||||
/* Interactive Hover */
|
||||
.hover-item {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
.hover-trigger:hover + .hover-item,
|
||||
.hover-item:hover {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* SVG Component Styling */
|
||||
svg text.text-black {
|
||||
fill: black;
|
||||
}
|
||||
svg line.text-black {
|
||||
stroke: black;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
svg text.dark\:text-white {
|
||||
fill: white;
|
||||
}
|
||||
svg line.dark\:text-white {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
<a href="./documents" class="w-full">
|
||||
<div
|
||||
class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col justify-around dark:text-white w-full text-sm"
|
||||
>
|
||||
<p class="text-2xl font-bold text-black dark:text-white">
|
||||
{{ .Data.DatabaseInfo.DocumentsSize }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-400">Documents</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="./activity" class="w-full">
|
||||
<div
|
||||
class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col justify-around dark:text-white w-full text-sm"
|
||||
>
|
||||
<p class="text-2xl font-bold text-black dark:text-white">
|
||||
{{ .Data.DatabaseInfo.ActivitySize }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-400">Activity Records</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="./progress" class="w-full">
|
||||
<div
|
||||
class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col justify-around dark:text-white w-full text-sm"
|
||||
>
|
||||
<p class="text-2xl font-bold text-black dark:text-white">
|
||||
{{ .Data.DatabaseInfo.ProgressSize }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-400">Progress Records</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col justify-around dark:text-white w-full text-sm"
|
||||
>
|
||||
<p class="text-2xl font-bold text-black dark:text-white">
|
||||
{{ .Data.DatabaseInfo.DevicesSize }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-400">Devices</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
{{ range $item := .Data.Streaks }}
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="relative w-full px-4 py-6 bg-white shadow-lg dark:bg-gray-700 rounded"
|
||||
>
|
||||
<p
|
||||
class="text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500"
|
||||
>
|
||||
{{ if eq $item.Window "WEEK" }}
|
||||
Weekly Read Streak
|
||||
{{ else }}
|
||||
Daily Read Streak
|
||||
{{ end }}
|
||||
</p>
|
||||
<div class="flex items-end my-6 space-x-2">
|
||||
<p class="text-5xl font-bold text-black dark:text-white">
|
||||
{{ $item.CurrentStreak }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="dark:text-white">
|
||||
<div
|
||||
class="flex items-center justify-between pb-2 mb-2 text-sm border-b border-gray-200"
|
||||
>
|
||||
<div>
|
||||
<p>
|
||||
{{ if eq $item.Window "WEEK" }} Current Weekly Streak {{ else }}
|
||||
Current Daily Streak {{ end }}
|
||||
</p>
|
||||
<div class="flex items-end text-sm text-gray-400">
|
||||
{{ $item.CurrentStreakStartDate }} ➞ {{ $item.CurrentStreakEndDate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-end font-bold">{{ $item.CurrentStreak }}</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between pb-2 mb-2 text-sm">
|
||||
<div>
|
||||
<p>
|
||||
{{ if eq $item.Window "WEEK" }}
|
||||
Best Weekly Streak
|
||||
{{ else }}
|
||||
Best Daily Streak
|
||||
{{ end }}
|
||||
</p>
|
||||
<div class="flex items-end text-sm text-gray-400">
|
||||
{{ $item.MaxStreakStartDate }} ➞ {{ $item.MaxStreakEndDate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-end font-bold">{{ $item.MaxStreak }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ 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}}
|
||||
160
templates/pages/home.tmpl
Normal file
160
templates/pages/home.tmpl
Normal file
@@ -0,0 +1,160 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Home{{ end }}
|
||||
{{ define "header" }}<a href="./">Home</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="w-full">
|
||||
<div class="relative w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded">
|
||||
<p class="absolute top-3 text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500">
|
||||
Daily Read Totals
|
||||
</p>
|
||||
{{ $data := (getSVGGraphData .Data.GraphData 800 70 )}}
|
||||
<svg viewBox="26 0 755 {{ $data.Height }}"
|
||||
preserveAspectRatio="none"
|
||||
width="100%"
|
||||
height="4em">
|
||||
<!-- Bezier Line Graph -->
|
||||
<path fill="#316BBE" fill-opacity="0.5" stroke="none" d="{{ $data.BezierPath }} {{ $data.BezierFill }}" />
|
||||
<path fill="none" stroke="#316BBE" d="{{ $data.BezierPath }}" />
|
||||
{{ range $index, $item := $data.LinePoints }}
|
||||
<line class="hover-trigger" stroke="black" stroke-opacity="0.0" stroke-width="{{ $data.Offset }}" x1="{{ $item.X }}" x2="{{ $item.X }}" y1="0" y2="{{ $data.Height }}"></line>
|
||||
<g class="hover-item">
|
||||
<line class="text-black dark:text-white" stroke-opacity="0.2" x1="{{ $item.X }}" x2="{{ $item.X }}" y1="30" y2="{{ $data.Height }}"></line>
|
||||
<text class="text-black dark:text-white" alignment-baseline="middle" transform="translate({{ $item.X }}, 5) translate(-30, 8)" font-size="10">
|
||||
{{ (index $.Data.GraphData $index).Date }}
|
||||
</text>
|
||||
<text class="text-black dark:text-white" alignment-baseline="middle" transform="translate({{ $item.X }}, 25) translate(-30, -2)" font-size="10">
|
||||
{{ (index $.Data.GraphData $index).MinutesRead }} minutes
|
||||
</text>
|
||||
</g>
|
||||
{{ end }}
|
||||
</svg>
|
||||
<style>
|
||||
/* Interactive Hover */
|
||||
.hover-item {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hover-trigger:hover+.hover-item,
|
||||
.hover-item:hover {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* SVG Component Styling */
|
||||
svg text.text-black {
|
||||
fill: black;
|
||||
}
|
||||
|
||||
svg line.text-black {
|
||||
stroke: black;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
svg text.dark\:text-white {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
svg line.dark\:text-white {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
<a href="./documents" class="w-full">
|
||||
<div class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded">
|
||||
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
|
||||
<p class="text-2xl font-bold text-black dark:text-white">{{ .Data.DatabaseInfo.DocumentsSize }}</p>
|
||||
<p class="text-sm text-gray-400">Documents</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="./activity" class="w-full">
|
||||
<div class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded">
|
||||
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
|
||||
<p class="text-2xl font-bold text-black dark:text-white">{{ .Data.DatabaseInfo.ActivitySize }}</p>
|
||||
<p class="text-sm text-gray-400">Activity Records</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="./progress" class="w-full">
|
||||
<div class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded">
|
||||
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
|
||||
<p class="text-2xl font-bold text-black dark:text-white">{{ .Data.DatabaseInfo.ProgressSize }}</p>
|
||||
<p class="text-sm text-gray-400">Progress Records</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="w-full">
|
||||
<div class="flex gap-4 w-full p-4 bg-white shadow-lg dark:bg-gray-700 rounded">
|
||||
<div class="flex flex-col justify-around dark:text-white w-full text-sm">
|
||||
<p class="text-2xl font-bold text-black dark:text-white">{{ .Data.DatabaseInfo.DevicesSize }}</p>
|
||||
<p class="text-sm text-gray-400">Devices</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
{{ range $item := .Data.Streaks }}
|
||||
<div class="w-full">
|
||||
<div class="relative w-full px-4 py-6 bg-white shadow-lg dark:bg-gray-700 rounded">
|
||||
<p class="text-sm font-semibold text-gray-700 border-b border-gray-200 w-max dark:text-white dark:border-gray-500">
|
||||
{{ if eq $item.Window "WEEK" }}
|
||||
Weekly Read Streak
|
||||
{{ else }}
|
||||
Daily Read Streak
|
||||
{{ end }}
|
||||
</p>
|
||||
<div class="flex items-end my-6 space-x-2">
|
||||
<p class="text-5xl font-bold text-black dark:text-white">{{ $item.CurrentStreak }}</p>
|
||||
</div>
|
||||
<div class="dark:text-white">
|
||||
<div class="flex items-center justify-between pb-2 mb-2 text-sm border-b border-gray-200">
|
||||
<div>
|
||||
<p>
|
||||
{{ if eq $item.Window "WEEK" }} Current Weekly Streak {{ else }}
|
||||
Current Daily Streak {{ end }}
|
||||
</p>
|
||||
<div class="flex items-end text-sm text-gray-400">
|
||||
{{ $item.CurrentStreakStartDate }} ➞ {{ $item.CurrentStreakEndDate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-end font-bold">{{ $item.CurrentStreak }}</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between pb-2 mb-2 text-sm">
|
||||
<div>
|
||||
<p>
|
||||
{{ if eq $item.Window "WEEK" }}
|
||||
Best Weekly Streak
|
||||
{{ else }}
|
||||
Best Daily Streak
|
||||
{{ end }}
|
||||
</p>
|
||||
<div class="flex items-end text-sm text-gray-400">{{ $item.MaxStreakStartDate }} ➞ {{ $item.MaxStreakEndDate }}</div>
|
||||
</div>
|
||||
<div class="flex items-end font-bold">{{ $item.MaxStreak }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ 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 }}
|
||||
@@ -1,211 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta
|
||||
name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent"
|
||||
/>
|
||||
<meta
|
||||
name="theme-color"
|
||||
content="#F3F4F6"
|
||||
media="(prefers-color-scheme: light)"
|
||||
/>
|
||||
<meta
|
||||
name="theme-color"
|
||||
content="#1F2937"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
/>
|
||||
|
||||
<title>AnthoLume - {{if .Register}}Register{{else}}Login{{end}}</title>
|
||||
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="stylesheet" href="./assets/style.css" />
|
||||
|
||||
<!-- Service Worker / Offline Cache Flush -->
|
||||
<script src="/assets/lib/idb-keyval.min.js"></script>
|
||||
<script src="/assets/common.js"></script>
|
||||
<script src="/assets/index.js"></script>
|
||||
|
||||
<style>
|
||||
/* ----------------------------- */
|
||||
/* -------- PWA Styling -------- */
|
||||
/* ----------------------------- */
|
||||
html,
|
||||
body {
|
||||
overscroll-behavior-y: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
html {
|
||||
height: calc(100% + env(safe-area-inset-bottom));
|
||||
padding: env(safe-area-inset-top) env(safe-area-inset-right) 0
|
||||
env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
/* No Scrollbar - IE, Edge, Firefox */
|
||||
* {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
/* No Scrollbar - WebKit */
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 dark:bg-gray-800 dark:text-white">
|
||||
<div class="flex flex-wrap w-full">
|
||||
<div class="flex flex-col w-full md:w-1/2">
|
||||
<div
|
||||
class="flex flex-col justify-center px-8 pt-8 my-auto md:justify-start md:pt-0 md:px-24 lg:px-32"
|
||||
>
|
||||
<p class="text-3xl text-center">Welcome.</p>
|
||||
<form
|
||||
class="flex flex-col pt-3 md:pt-8"
|
||||
{{if
|
||||
.Register}}action="./register"
|
||||
{{else}}action="./login"
|
||||
{{end}}
|
||||
method="POST"
|
||||
>
|
||||
<div class="flex flex-col pt-4">
|
||||
<div class="flex relative">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/user" (dict "Size" 15) }}
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
placeholder="Username"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col pt-4 mb-12">
|
||||
<div class="flex relative">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/password" (dict "Size" 15) }}
|
||||
</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"
|
||||
/>
|
||||
<span class="absolute -bottom-5 text-red-400 text-xs"
|
||||
>{{ .Error }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full px-4 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
{{if .Register}}
|
||||
<span class="w-full"> Register </span>
|
||||
{{else}}
|
||||
<span class="w-full"> Submit </span>
|
||||
{{end}}
|
||||
</button>
|
||||
</form>
|
||||
<div class="pt-12 pb-12 text-center">
|
||||
{{ if .Config.RegistrationEnabled }} {{ if .Register }}
|
||||
<p>
|
||||
Trying to login?
|
||||
<a href="./login" class="font-semibold underline">
|
||||
Login here.
|
||||
</a>
|
||||
</p>
|
||||
{{else}}
|
||||
<p>
|
||||
Don't have an account?
|
||||
<a href="./register" class="font-semibold underline">
|
||||
Register here.
|
||||
</a>
|
||||
</p>
|
||||
{{end}} {{ end }}
|
||||
<p class="mt-4">
|
||||
<a href="./local" class="font-semibold underline">
|
||||
Offline / Local Mode
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="hidden image-fader w-1/2 shadow-2xl h-screen relative md:block"
|
||||
>
|
||||
<img
|
||||
class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book1.jpg"
|
||||
/>
|
||||
<img
|
||||
class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book2.jpg"
|
||||
/>
|
||||
<img
|
||||
class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book3.jpg"
|
||||
/>
|
||||
<img
|
||||
class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book4.jpg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.image-fader img {
|
||||
position: absolute;
|
||||
animation-name: imagefade;
|
||||
animation-iteration-count: infinite;
|
||||
animation-duration: 60s;
|
||||
}
|
||||
|
||||
@keyframes imagefade {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
17% {
|
||||
opacity: 1;
|
||||
}
|
||||
25% {
|
||||
opacity: 0;
|
||||
}
|
||||
92% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.image-fader img:nth-of-type(1) {
|
||||
animation-delay: 45s;
|
||||
}
|
||||
.image-fader img:nth-of-type(2) {
|
||||
animation-delay: 30s;
|
||||
}
|
||||
.image-fader img:nth-of-type(3) {
|
||||
animation-delay: 15s;
|
||||
}
|
||||
.image-fader img:nth-of-type(4) {
|
||||
animation-delay: 0;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- https://stackoverflow.com/questions/60748752/change-an-image-after-some-time -->
|
||||
173
templates/pages/login.tmpl
Normal file
173
templates/pages/login.tmpl
Normal file
@@ -0,0 +1,173 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=0.90, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style"
|
||||
content="black-translucent" />
|
||||
<meta name="theme-color"
|
||||
content="#F3F4F6"
|
||||
media="(prefers-color-scheme: light)" />
|
||||
<meta name="theme-color"
|
||||
content="#1F2937"
|
||||
media="(prefers-color-scheme: dark)" />
|
||||
<title>AnthoLume - {{ if .Register }}Register{{ else }}Login{{ end }}</title>
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="stylesheet" href="./assets/style.css" />
|
||||
<!-- Service Worker / Offline Cache Flush -->
|
||||
<script src="/assets/lib/idb-keyval.min.js"></script>
|
||||
<script src="/assets/common.js"></script>
|
||||
<script src="/assets/index.js"></script>
|
||||
<style>
|
||||
/* ----------------------------- */
|
||||
/* -------- PWA Styling -------- */
|
||||
/* ----------------------------- */
|
||||
html,
|
||||
body {
|
||||
overscroll-behavior-y: none;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
html {
|
||||
height: calc(100% + env(safe-area-inset-bottom));
|
||||
padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
/* No Scrollbar - IE, Edge, Firefox */
|
||||
* {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
/* No Scrollbar - WebKit */
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 dark:bg-gray-800 dark:text-white">
|
||||
<div class="flex flex-wrap w-full">
|
||||
<div class="flex flex-col w-full md:w-1/2">
|
||||
<div class="flex flex-col justify-center px-8 pt-8 my-auto md:justify-start md:pt-0 md:px-24 lg:px-32">
|
||||
<p class="text-3xl text-center">Welcome.</p>
|
||||
<form
|
||||
class="flex flex-col pt-3 md:pt-8"
|
||||
{{if
|
||||
.Register}}action="./register"
|
||||
{{ else }}action="./login"
|
||||
{{ end }}
|
||||
method="POST"
|
||||
>
|
||||
<div class="flex flex-col pt-4">
|
||||
<div class="flex relative">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/user" (dict "Size" 15) }}
|
||||
</span>
|
||||
<input type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
placeholder="Username" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col pt-4 mb-12">
|
||||
<div class="flex relative">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/password" (dict "Size" 15) }}
|
||||
</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" />
|
||||
<span class="absolute -bottom-5 text-red-400 text-xs">{{ .Error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="w-full px-4 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
{{ if .Register }}
|
||||
<span class="w-full">Register</span>
|
||||
{{ else }}
|
||||
<span class="w-full">Submit</span>
|
||||
{{ end }}
|
||||
</button>
|
||||
</form>
|
||||
<div class="pt-12 pb-12 text-center">
|
||||
{{ if .Config.RegistrationEnabled }} {{ if .Register }}
|
||||
<p>
|
||||
Trying to login?
|
||||
<a href="./login" class="font-semibold underline">Login here.</a>
|
||||
</p>
|
||||
{{ else }}
|
||||
<p>
|
||||
Don't have an account?
|
||||
<a href="./register" class="font-semibold underline">Register here.</a>
|
||||
</p>
|
||||
{{ end }} {{ end }}
|
||||
<p class="mt-4">
|
||||
<a href="./local" class="font-semibold underline">Offline / Local Mode</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden image-fader w-1/2 shadow-2xl h-screen relative md:block">
|
||||
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book1.jpg" />
|
||||
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book2.jpg" />
|
||||
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book3.jpg" />
|
||||
<img class="w-full h-screen object-cover ease-in-out top-0 left-0"
|
||||
src="/assets/images/book4.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.image-fader img {
|
||||
position: absolute;
|
||||
animation-name: imagefade;
|
||||
animation-iteration-count: infinite;
|
||||
animation-duration: 60s;
|
||||
}
|
||||
|
||||
@keyframes imagefade {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
17% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
25% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
92% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.image-fader img:nth-of-type(1) {
|
||||
animation-delay: 45s;
|
||||
}
|
||||
|
||||
.image-fader img:nth-of-type(2) {
|
||||
animation-delay: 30s;
|
||||
}
|
||||
|
||||
.image-fader img:nth-of-type(3) {
|
||||
animation-delay: 15s;
|
||||
}
|
||||
|
||||
.image-fader img:nth-of-type(4) {
|
||||
animation-delay: 0;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,49 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Progress{{end}} {{define "header"}}
|
||||
<a href="./progress">Progress</a>
|
||||
{{end}} {{define "content"}}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Document
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Device
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Percent
|
||||
</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Time
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="4">No Results</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{range $progress := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<a href="./documents/{{ $progress.DocumentID }}">{{ $progress.Author }} - {{ $progress.Title }}</p></a>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $progress.DeviceName }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $progress.Percentage }}%</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $progress.CreatedAt }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
44
templates/pages/progress.tmpl
Normal file
44
templates/pages/progress.tmpl
Normal file
@@ -0,0 +1,44 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Progress{{ end }}
|
||||
{{ define "header" }}<a href="./progress">Progress</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Device</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Percent</th>
|
||||
<th class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="4">No Results</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ range $progress := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<a href="./documents/{{ $progress.DocumentID }}">{{ $progress.Author }} - {{ $progress.Title }}
|
||||
</p>
|
||||
</a>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $progress.DeviceName }}</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $progress.Percentage }}%</p>
|
||||
</td>
|
||||
<td class="p-3 border-b border-gray-200">
|
||||
<p>{{ $progress.CreatedAt }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,155 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Search{{end}} {{define "header"}}
|
||||
<a href="./search">Search</a>
|
||||
{{end}} {{define "content"}}
|
||||
<div class="w-full flex flex-col md:flex-row gap-4">
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<div
|
||||
class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
<form class="flex gap-4 flex-col lg:flex-row" action="./search">
|
||||
<div class="flex flex-col w-full grow">
|
||||
<div class="flex relative">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/search2" (dict "Size" 15) }}
|
||||
</span>
|
||||
<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 class="flex relative min-w-[12em]">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/documents" (dict "Size" 15) }}
|
||||
</span>
|
||||
<select
|
||||
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
id="source"
|
||||
name="source"
|
||||
>
|
||||
<option value="Annas Archive">Annas Archive</option>
|
||||
<option value="LibGen Fiction">LibGen Fiction</option>
|
||||
<option value="LibGen Non-fiction">LibGen Non-fiction</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Search</span>
|
||||
</button>
|
||||
</form>
|
||||
{{ if .SearchErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .SearchErrorMessage }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table
|
||||
class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm md:text-sm"
|
||||
>
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
class="w-12 p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
|
||||
></th>
|
||||
<th
|
||||
scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
|
||||
>
|
||||
Document
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
|
||||
>
|
||||
Series
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
|
||||
>
|
||||
Type
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
|
||||
>
|
||||
Size
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="p-3 hidden md:block font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"
|
||||
>
|
||||
Date
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="6">No Results</td>
|
||||
</tr>
|
||||
{{ end }} {{range $item := .Data }}
|
||||
<tr>
|
||||
<td
|
||||
class="p-3 border-b border-gray-200 text-gray-500 dark:text-gray-500"
|
||||
>
|
||||
<form action="./search" method="POST">
|
||||
<input
|
||||
class="hidden"
|
||||
type="text"
|
||||
id="source"
|
||||
name="source"
|
||||
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>
|
||||
{{end}}
|
||||
109
templates/pages/search.tmpl
Normal file
109
templates/pages/search.tmpl
Normal file
@@ -0,0 +1,109 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Search{{ end }}
|
||||
{{ define "header" }}<a href="./search">Search</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="w-full flex flex-col md:flex-row gap-4">
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<div class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
<form class="flex gap-4 flex-col lg:flex-row" action="./search">
|
||||
<div class="flex flex-col w-full grow">
|
||||
<div class="flex relative">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/search2" (dict "Size" 15) }}
|
||||
</span>
|
||||
<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 class="flex relative min-w-[12em]">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/documents" (dict "Size" 15) }}
|
||||
</span>
|
||||
<select class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
id="source"
|
||||
name="source">
|
||||
<option value="Annas Archive">Annas Archive</option>
|
||||
<option value="LibGen Fiction">LibGen Fiction</option>
|
||||
<option value="LibGen Non-fiction">LibGen Non-fiction</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Search</span>
|
||||
</button>
|
||||
</form>
|
||||
{{ if .SearchErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .SearchErrorMessage }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="inline-block min-w-full overflow-hidden rounded shadow">
|
||||
<table class="min-w-full leading-normal bg-white dark:bg-gray-700 text-sm md:text-sm">
|
||||
<thead class="text-gray-800 dark:text-gray-400">
|
||||
<tr>
|
||||
<th scope="col"
|
||||
class="w-12 p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800"></th>
|
||||
<th scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Document</th>
|
||||
<th scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Series</th>
|
||||
<th scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Type</th>
|
||||
<th scope="col"
|
||||
class="p-3 font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">Size</th>
|
||||
<th scope="col"
|
||||
class="p-3 hidden md:block font-normal text-left uppercase border-b border-gray-200 dark:border-gray-800">
|
||||
Date
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-black dark:text-white">
|
||||
{{ if not .Data }}
|
||||
<tr>
|
||||
<td class="text-center p-3" colspan="6">No Results</td>
|
||||
</tr>
|
||||
{{ end }} {{ range $item := .Data }}
|
||||
<tr>
|
||||
<td class="p-3 border-b border-gray-200 text-gray-500 dark:text-gray-500">
|
||||
<form action="./search" method="POST">
|
||||
<input class="hidden"
|
||||
type="text"
|
||||
id="source"
|
||||
name="source"
|
||||
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>
|
||||
{{ end }}
|
||||
@@ -1,165 +0,0 @@
|
||||
{{template "base" .}} {{define "title"}}Settings{{end}} {{define "header"}}
|
||||
<a href="./settings">Settings</a>
|
||||
{{end}} {{define "content"}}
|
||||
<div class="w-full flex flex-col md:flex-row gap-4">
|
||||
<div>
|
||||
<div
|
||||
class="flex flex-col p-4 items-center rounded shadow-lg md:w-60 lg:w-80 bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
{{ template "svg/user" (dict "Size" 60) }}
|
||||
<p class="text-lg">{{ .Authorization.UserName }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<div
|
||||
class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
<p class="text-lg font-semibold mb-2">Change Password</p>
|
||||
<form
|
||||
class="flex gap-4 flex-col lg:flex-row"
|
||||
action="./settings"
|
||||
method="POST"
|
||||
>
|
||||
<div class="flex flex-col grow">
|
||||
<div class="flex relative">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/password" (dict "Size" 15) }}
|
||||
</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 class="flex flex-col grow">
|
||||
<div class="flex relative">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/password" (dict "Size" 15) }}
|
||||
</span>
|
||||
<input
|
||||
type="password"
|
||||
id="new_password"
|
||||
name="new_password"
|
||||
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
placeholder="New Password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Submit</span>
|
||||
</button>
|
||||
</form>
|
||||
{{ if .PasswordErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
|
||||
{{ else if .PasswordMessage }}
|
||||
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white"
|
||||
>
|
||||
<p class="text-lg font-semibold mb-2">Change Time Offset</p>
|
||||
<form
|
||||
class="flex gap-4 flex-col lg:flex-row"
|
||||
action="./settings"
|
||||
method="POST"
|
||||
>
|
||||
<div class="flex relative grow">
|
||||
<span
|
||||
class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm"
|
||||
>
|
||||
{{ template "svg/clock" (dict "Size" 15) }}
|
||||
</span>
|
||||
<select
|
||||
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
id="time_offset"
|
||||
name="time_offset"
|
||||
>
|
||||
{{ range $item := getUTCOffsets }}
|
||||
<option
|
||||
{{ if (eq $item.Value $.Data.TimeOffset) }}selected{{ end }}
|
||||
value="{{ $item.Value }}"
|
||||
>
|
||||
{{ $item.Name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2"
|
||||
>
|
||||
<span class="w-full">Submit</span>
|
||||
</button>
|
||||
</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 }} {{ 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>
|
||||
{{end}}
|
||||
124
templates/pages/settings.tmpl
Normal file
124
templates/pages/settings.tmpl
Normal file
@@ -0,0 +1,124 @@
|
||||
{{ template "base" . }}
|
||||
{{ define "title" }}Settings{{ end }}
|
||||
{{ define "header" }}<a href="./settings">Settings</a>{{ end }}
|
||||
{{ define "content" }}
|
||||
<div class="w-full flex flex-col md:flex-row gap-4">
|
||||
<div>
|
||||
<div class="flex flex-col p-4 items-center rounded shadow-lg md:w-60 lg:w-80 bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
{{ template "svg/user" (dict "Size" 60) }}
|
||||
<p class="text-lg">{{ .Authorization.UserName }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 grow">
|
||||
<div class="flex flex-col gap-2 grow p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
<p class="text-lg font-semibold mb-2">Change Password</p>
|
||||
<form class="flex gap-4 flex-col lg:flex-row"
|
||||
action="./settings"
|
||||
method="POST">
|
||||
<div class="flex flex-col grow">
|
||||
<div class="flex relative">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/password" (dict "Size" 15) }}
|
||||
</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 class="flex flex-col grow">
|
||||
<div class="flex relative">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/password" (dict "Size" 15) }}
|
||||
</span>
|
||||
<input type="password"
|
||||
id="new_password"
|
||||
name="new_password"
|
||||
class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
placeholder="New Password" />
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Submit</span>
|
||||
</button>
|
||||
</form>
|
||||
{{ if .PasswordErrorMessage }}
|
||||
<span class="text-red-400 text-xs">{{ .PasswordErrorMessage }}</span>
|
||||
{{ else if .PasswordMessage }}
|
||||
<span class="text-green-400 text-xs">{{ .PasswordMessage }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="flex flex-col grow gap-2 p-4 rounded shadow-lg bg-white dark:bg-gray-700 text-gray-500 dark:text-white">
|
||||
<p class="text-lg font-semibold mb-2">Change Time Offset</p>
|
||||
<form class="flex gap-4 flex-col lg:flex-row"
|
||||
action="./settings"
|
||||
method="POST">
|
||||
<div class="flex relative grow">
|
||||
<span class="inline-flex items-center px-3 border-t bg-white border-l border-b border-gray-300 text-gray-500 shadow-sm text-sm">
|
||||
{{ template "svg/clock" (dict "Size" 15) }}
|
||||
</span>
|
||||
<select class="flex-1 appearance-none rounded-none border border-gray-300 w-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
|
||||
id="time_offset"
|
||||
name="time_offset">
|
||||
{{ range $item := getUTCOffsets }}
|
||||
<option {{ if (eq $item.Value $.Data.TimeOffset) }}selected{{ end }} value="{{ $item.Value }}">
|
||||
{{ $item.Name }}
|
||||
</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="px-10 py-2 text-base font-semibold text-center text-white transition duration-200 ease-in bg-black shadow-md hover:text-black hover:bg-white focus:outline-none focus:ring-2">
|
||||
<span class="w-full">Submit</span>
|
||||
</button>
|
||||
</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 }}
|
||||
{{ 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>
|
||||
{{ end }}
|
||||
Reference in New Issue
Block a user