Initial commit

This commit is contained in:
Thomas Miceli
2023-03-14 16:22:52 +01:00
commit bee5d045c3
52 changed files with 8560 additions and 0 deletions

9
templates/base/admin_footer.html vendored Normal file
View File

@ -0,0 +1,9 @@
{{ define "admin_footer" }}
{{ if .urlPage }}
<div class="flex mt-4 justify-center space-x-2">
{{ template "pagination" . }}
</div>
{{ end }}
</main>
</div>
{{ end }}

22
templates/base/admin_header.html vendored Normal file
View File

@ -0,0 +1,22 @@
{{ define "admin_header" }}
<div class="py-10">
<header class="pb-4">
<div>
<h1 class="text-2xl font-bold leading-tight">Admin panel</h1>
</div>
</header>
<main>
<div class="mb-4">
<div class="">
<nav class="flex space-x-4" aria-label="Tabs">
<a href="/admin" class="{{ if eq .adminHeaderPage "index" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}">General</a>
<a href="/admin/users" class="{{ if eq .adminHeaderPage "users" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}" aria-current="page">Users</a>
<a href="/admin/gists" class="{{ if eq .adminHeaderPage "gists" }}bg-gray-700 text-slate-300 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md
{{ else }} text-gray-400 hover:text-slate-300 px-3 py-2 font-medium text-sm rounded-md {{ end }}" aria-current="page">Gists</a>
</nav>
</div>
</div>
{{ end }}

21
templates/base/base_footer.html vendored Normal file
View File

@ -0,0 +1,21 @@
{{ define "footer" }}
<p class="text-slate-400 py-8 [&>*]:mx-1.5 flex">
<span>
<a target="_blank" style="margin-left: 0 !important;" class="text-gray-500 hover:text-white font-bold inline-flex" href="https://github.com/thomiceli/opengist">
<span class="mr-1">Opengist</span>
<svg width="24" height="24" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.606 9.606 0 0112 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48C19.137 20.107 22 16.373 22 11.969 22 6.463 17.522 2 12 2z"></path>
</svg>
</a>
</span>
<span class="text-gray-500">Load: <span class="font-bold">{{ loadedTime .loadStartTime }}</span></span>
</p>
</div>
</div>
</body>
</html>
{{ end }}

142
templates/base/base_header.html vendored Normal file
View File

@ -0,0 +1,142 @@
{{ define "header" }}
<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="http://localhost:3000/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
html {
background-color: #0d1117;
}
</style>
<script type="module" src="http://localhost:3000/main.js"></script>
{{ if .htmlTitle }}
<title>{{ .htmlTitle }} - Opengist</title>
{{ else }}
<title>Opengist</title>
{{ end }}
</head>
<body class="h-full">
<div id="app" class="text-white min-h-full bg-gray-900">
<div class="min-h-full">
<nav class="bg-gray-800">
<div class="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
<div class="relative flex items-center justify-between h-16">
<div class="absolute inset-y-0 left-0 flex items-center sm:hidden">
<!-- Mobile menu button-->
<button id="main-menu-button" type="button" class="inline-flex items-center justify-center p-2 rounded-md text-slate-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white" aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg id="main-menu-open" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg id="main-menu-close" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
<div class="flex-shrink-0 flex items-center">
<a href="/">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 flex text-primary-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
</a>
</div>
<div class="hidden sm:block sm:ml-6">
<div class="flex space-x-4">
<a href="/all" class="text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">All</a>
{{ if .userLogged }}
<a href="/{{ .userLogged.Username }}" class="text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">My gists</a>
{{ end }}
</div>
</div>
</div>
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
{{ if .userLogged }}
{{ if .userLogged.IsAdmin }}
<a href="/admin" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Admin</a>
{{ end }}
<a href="/ssh-keys" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">SSH Keys</a>
<a href="/logout" id="logged-button" class="inline-flex text-slate-300 hover:bg-rose-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">
<p class="text-slate-300 mr-1 username">{{ .userLogged.Username }}</p>
<p class="text-slate-300 mr-1 logout hidden">Logout</p>
<span class="sr-only">User</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-slate-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
</a>
{{ else }}
{{ if not .signupDisabled }}
<a href="/register" class="inline-flex text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">
<p class="text-slate-300 mr-1">Register</p>
</a>
{{ end }}
<a href="/login" class="inline-flex text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">
<p class="text-slate-300 mr-1">Login</p>
</a>
{{ end }}
</div>
</div>
</div>
<!-- Mobile menu -->
<div class="sm:hidden hidden" id="mobile-menu">
<div class="px-2 pt-2 pb-3 space-y-1">
<a href="/all" class="bg-gray-900 text-white block px-3 py-2 rounded-md text-base font-medium" aria-current="page">All</a>
{{ if .userLogged }}
<a href="/{{ .userLogged.Username }}" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">My gists</a>
<a href="/ssh-keys" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">SSH Keys</a>
{{ if .userLogged.IsAdmin }}
<a href="/admin" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Admin</a>
{{ end }}
{{ end }}
</div>
</div>
</nav>
</div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-slate-300">
<div>
{{range .flashErrors}}
<div class="mt-4 rounded-md bg-gray-800 border-l-4 border-rose-400 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-rose-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<p class="text-sm text-rose-400">{{.}}</p>
</div>
</div>
</div>
{{end}}
{{range .flashSuccess}}
<div class="mt-4 rounded-md bg-gray-800 border-l-4 border-primary-400 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary-400" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<p class="text-sm text-primary-400">{{.}}</p>
</div>
</div>
</div>
{{end}}
</div>
{{ end }}

4
templates/base/gist_footer.html vendored Normal file
View File

@ -0,0 +1,4 @@
{{ define "gist_footer" }}
</main>
</div>
{{ end }}

165
templates/base/gist_header.html vendored Normal file
View File

@ -0,0 +1,165 @@
{{ define "gist_header" }}
<div class="py-10">
<header>
<div class="flex">
<h1 class="text-2xl font-bold leading-tight break-all">
<a href="/{{ .gist.User.Username }}">{{ .gist.User.Username }}</a> <span class="text-slate-300">/</span> <a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}">{{ .gist.Title }}</a>
</h1>
{{ if .userLogged }}
<form id="like" class="ml-auto flex items-center" method="post" action="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/like?redirecturl={{ .currentUrl }}">
{{ .csrfHtml }}
<button type="submit" class="ml-auto focus-within:z-10 text-slate-300 relative inline-flex items-center space-x-2 rounded-l-md border border-gray-600 bg-gray-800 px-2 py-1.5 text-xs font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3">
{{ if not .hasLiked }}
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
Like
{{ else }}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-4 h-4 mr-2">
<path d="M11.645 20.91l-.007-.003-.022-.012a15.247 15.247 0 01-.383-.218 25.18 25.18 0 01-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0112 5.052 5.5 5.5 0 0116.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 01-4.244 3.17 15.247 15.247 0 01-.383.219l-.022.012-.007.004-.003.001a.752.752 0 01-.704 0l-.003-.001z" />
</svg>
Unlike
{{ end }}
</button>
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/likes" class="text-slate-300 relative inline-flex align-middle items-center space-x-2 rounded-r-md border border-gray-700 bg-gray-900 px-2 py-1.5 -ml-px text-xs font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
{{ .gist.NbLikes }}
</a>
</form>
{{ else }}
<div class="ml-auto flex items-center">
<a href="/login" type="submit" class="ml-auto focus-within:z-10 text-slate-300 relative inline-flex items-center space-x-2 rounded-l-md border border-gray-600 bg-gray-800 px-2 py-1.5 text-xs font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-2">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
Like
</a>
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/likes" class="text-slate-300 relative inline-flex align-middle items-center space-x-2 rounded-r-md border border-gray-700 bg-gray-900 px-2 py-1.5 -ml-px text-xs font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
{{ .gist.NbLikes }}
</a>
</div>
{{ end }}
{{ if .userLogged }}{{ if eq .gist.User.Username .userLogged.Username }}
<form id="visibility" class="ml-2" method="post" action="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/visibility">
{{ .csrfHtml }}
<button type="submit" class="ml-auto text-slate-300 relative inline-flex items-center space-x-2 rounded-md border border-gray-600 bg-gray-800 px-2 py-1.5 text-xs font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3">
{{ if .gist.Private }}
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
Make public
{{ else }}
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
</svg>
Make unlisted
{{ end }}
</button>
</form>
<!-- Small hack to avoid ugly button behavior -->
<form>
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/edit" class="ml-2 relative inline-flex items-center space-x-2 rounded-md border border-gray-600 bg-gray-800 px-2 py-1.5 text-xs font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
Edit
</a>
</form>
<form id="delete" onsubmit="alert('Are you sure you want to delete this gist ?')" class="ml-2" method="post" action="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/delete">
{{ .csrfHtml }}
<button type="submit" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-600 bg-gray-800 px-2 py-1.5 text-xs font-medium text-rose-400 hover:bg-rose-700 hover:border-rose-600 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
Delete
</button>
</form>
{{ end }}{{ end }}
</div>
<p class="mt-1 max-w-2xl text-sm text-slate-500">Last active <span class="moment-timestamp"> {{ .gist.UpdatedAt }} </span>
{{ if .gist.Private }}<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-700 text-slate-300"> Unlisted </span>
{{else}}<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-emerald-700 text-emerald-300"> Public </span>{{ end }}
</p>
<p class="mt-3 max-w-2xl text-slate-300">{{ .gist.Description }}</p>
</header>
<main class="mt-4">
<div class="my-4">
<div class="sm:hidden">
<label for="gist-tabs" class="sr-only">Select a tab</label>
<select id="gist-tabs" name="tabs" class="block bg-gray-800 w-full pl-3 pr-10 py-2 text-base border-gray-700 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm rounded-md">
<option {{ if eq .page "code"}}selected{{end}} data-url="/{{ .gist.User.Username }}/{{ .gist.Uuid }}">Code</option>
<option {{ if eq .page "revisions"}}selected{{end}} data-url="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/revisions">Revisions ({{ if .nbCommits }}{{ .nbCommits }}{{else}}0{{ end }})</option>
</select>
</div>
<div class="hidden sm:block">
<div class="border-b flex border-gray-700">
<nav class="-mb-px flex-auto space-x-4" aria-label="Tabs">
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}" class="inline-flex items-center {{ if eq .page "code"}}border-primary-500 {{else}}border-transparent text-slate-300 hover:border-gray-300{{end}} hover:text-slate-300 whitespace-nowrap py-2 px-1 border-b-2 font-medium text-sm" aria-current="page">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.25 9.75L16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0020.25 18V6A2.25 2.25 0 0018 3.75H6A2.25 2.25 0 003.75 6v12A2.25 2.25 0 006 20.25z" />
</svg>
Code
</a>
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/revisions" class="inline-flex items-center {{ if eq .page "revisions"}}border-primary-500 {{else}}border-transparent text-slate-300 hover:border-gray-300{{end}} hover:text-slate-300 whitespace-nowrap py-2 px-1 border-b-2 font-medium text-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />
</svg>
Revisions
<span class="inline-flex items-center ml-1 px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-700 text-slate-300"> {{ if .nbCommits }}{{ .nbCommits }}{{else}}0{{ end }} </span>
</a>
</nav>
<div class="float-right inline-flex items-center space-x-2">
<div>
<div class="flex rounded-md shadow-sm">
<div class="relative">
<button type="button" id="gist-menu-toggle" class="relative text-xs inline-flex items-center space-x-2 rounded-l-md border border-gray-600 bg-gray-800 px-2 py-1.5 text-sm font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3 focus-within:z-10 -mr-px">
<span id="gist-menu-title">Clone via HTTP</span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
</button>
<div class="absolute left-0 z-10 mt-2 w-56 origin-top-left bg-gray-800 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
<div class="py-1 cursor-pointer border-1 rounded-md border-gray-700 hidden" id="gist-menu-copy" role="none">
<div class="text-slate-300 block px-4 py-2 text-sm hover:bg-gray-700 gist-menu-item" role="menuitem" id="gist-menu-http" data-link="{{ .httpCloneUrl }}"><p>Clone via HTTP</p>
<p class="text-xs font-normal text-gray-400">Clone with Git using HTTP basic authentication.</p>
</div>
<div class="text-slate-300 block px-4 py-2 text-sm hover:bg-gray-700 gist-menu-item" role="menuitem" id="gist-menu-ssh" data-link="{{ .ssh_clone_url }}"><p>Clone via SSH</p>
<p class="text-xs font-normal text-gray-400">Clone with Git using an SSH key.</p>
</div>
<div class="text-slate-300 block px-4 py-2 text-sm hover:bg-gray-700 gist-menu-item" role="menuitem" id="gist-menu-embed" data-link="(soon)"><p>Embed</p>
<p class="text-xs font-normal text-gray-400">Embed this gist in your website. (soon)</p>
</div>
<div class="text-slate-300 block px-4 py-2 text-sm hover:bg-gray-700 gist-menu-item" role="menuitem" id="gist-menu-share" data-link="{{ .httpCopyUrl }}"><p>Share</p>
<p class="text-xs font-normal text-gray-400">Copy shareable link for this gist.</p>
</div>
</div>
</div>
</div>
<div class="relative flex flex-grow items-stretch focus-within:z-10">
<input id="gist-menu-input" value="{{ .httpCloneUrl }}" class="block code bg-gray-900 w-full rounded-none border border-gray-600 focus:border-primary-500 focus:ring-primary-500 focus:outline-none focus:ring-1 text-xs px-2">
</div>
<button id="gist-menu-button-copy" type="button" class="relative text-xs -ml-px inline-flex items-center space-x-2 rounded-r-md border border-gray-600 bg-gray-800 px-2 py-1 text-sm font-medium text-slate-300 hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192.373-.03.748-.057 1.123-.08M15.75 18H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5A3.375 3.375 0 006.375 7.5H5.25m11.9-3.664A2.251 2.251 0 0015 2.25h-1.5a2.251 2.251 0 00-2.15 1.586m5.8 0c.065.21.1.433.1.664v.75h-6V4.5c0-.231.035-.454.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 00-9-9z" />
</svg>
</button>
</div>
</div>
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/archive/{{ .revision }}" class="text-slate-300 rounded border border-gray-600 bg-gray-800 px-2.5 py-2 text-xs font-medium text-white shadow-sm hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:outline-none focus:ring-1 focus:border-primary-500 focus:ring-primary-500 leading-3">
Download ZIP</a>
</div>
</div>
</div>
{{ if .revision }} {{ if ne .revision "HEAD" }}
<p class="italic text-xs mt-3">Revision <span class="revision-text">{{ .revision }}</span></p>
{{ end }} {{ end }}
</div>
{{ end }}

31
templates/base/pagination.html vendored Normal file
View File

@ -0,0 +1,31 @@
{{ define "pagination" }}
<div class="flex justify-center space-x-2">
{{ if .prevPage }}
<a href="/{{ .urlPage }}?page={{ .prevPage }}{{ .urlParams }}" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-900 bg-gray-900 px-2 py-1.5 font-medium text-slate-300 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 text-sm leading-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="mr-1 w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
Newer</a>
{{ else }}
<span class="relative inline-flex items-center space-x-2 rounded-md border border-gray-900 bg-gray-900 px-2 py-1.5 font-medium text-gray-500 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 text-sm leading-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="mr-1 w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
Newer</span>
{{ end }}
{{ if .nextPage }}
<a href="/{{ .urlPage }}?page={{ .nextPage }}{{ .urlParams }}" class="relative inline-flex items-center space-x-2 rounded-md border border-gray-900 bg-gray-900 px-2 py-1.5 font-medium text-slate-300 hover:border-gray-500 hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 text-sm leading-4">Older
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="ml-1 w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</a>
{{ else }}
<span class="relative inline-flex items-center space-x-2 rounded-md border border-gray-900 bg-gray-900 px-2 py-1.5 font-medium text-gray-500 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 text-sm leading-4">Older
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="ml-1 w-4 h-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</span>
{{ end }}
</div>
{{ end }}

43
templates/pages/admin_gists.html vendored Normal file
View File

@ -0,0 +1,43 @@
{{ template "header" .}}
{{ template "admin_header" .}}
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8 bg-gray-800 rounded-md border border-gray-700">
<table class="min-w-full divide-y divide-gray-500">
<thead>
<tr>
<th scope="col" class="whitespace-nowrap py-3.5 pl-4 pr-3 text-left text-sm font-bold text-slate-300 sm:pl-0">ID</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300">Title</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300">User</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300">Private ?</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300"># files</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300"># likes</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300">Created at</th>
<th scope="col" class="relative whitespace-nowrap py-3.5 pl-3 pr-4 sm:pr-0">
<span class="sr-only">Delete</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-500">
{{ range $gist := .data }}
<tr>
<td class="whitespace-nowrap py-2 pl-4 pr-3 text-sm text-slate-300 sm:pl-0">{{ $gist.ID }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><a href="/{{ $gist.User.Username }}/{{ $gist.Uuid }}">{{ $gist.Title }}</a></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><a href="/{{ $gist.User.Username }}">{{ $gist.User.Username }}</a></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300">{{ $gist.Private }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300">{{ $gist.NbFiles }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300">{{ $gist.NbLikes }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><span class="moment-timestamp-date">{{ $gist.CreatedAt }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="/admin/gists/{{ $gist.ID }}/delete" method="POST" onsubmit="return confirm('Do you want to delete this user ?')">
{{ $.csrfHtml }}
<button type="submit" class="text-rose-500 hover:text-rose-600">Delete</button>
</form>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ template "admin_footer" .}}
{{ template "footer" .}}

55
templates/pages/admin_index.html vendored Normal file
View File

@ -0,0 +1,55 @@
{{ template "header" .}}
{{ template "admin_header" .}}
<div class="sm:flex sm:space-x-4 space-y-4 sm:space-y-0">
<div class="sm:overflow-hidden ">
<div class="space-y-2 bg-gray-800 py-6 px-6 rounded-md border border-gray-700">
<div>
<span class="text-base font-bold leading-6 text-slate-300">Versions</span>
</div>
<table class="table-fixed">
<tbody>
<tr>
<td class="whitespace-nowrap py-2 pr-3 text-sm text-slate-300 ">Opengist</td>
<td class="whitespace-nowrap px-2 py-2 text-sm font-medium text-slate-300">{{ .opengistVersion }}</td>
</tr>
<tr>
<td class="whitespace-nowrap py-2 pr-3 text-sm text-slate-300 ">Go</td>
<td class="whitespace-nowrap px-2 py-2 text-sm font-medium text-slate-300">{{ .goVersion }}</td>
</tr>
<tr>
<td class="whitespace-nowrap py-2 pr-3 text-sm text-slate-300 ">Git</td>
<td class="whitespace-nowrap px-2 py-2 text-sm font-medium text-slate-300">{{ .gitVersion }} </td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sm:overflow-hidden ">
<div class="space-y-2 bg-gray-800 py-6 px-6 rounded-md border border-gray-700">
<div>
<span class="text-base font-bold leading-6 text-slate-300">Stats</span>
</div>
<table class="table-fixed">
<tbody>
<tr>
<td class="whitespace-nowrap py-2 pr-3 text-sm text-slate-300 ">Users</td>
<td class="whitespace-nowrap px-2 py-2 text-sm font-medium text-slate-300">{{ .countUsers }}</td>
</tr>
<tr>
<td class="whitespace-nowrap py-2 pr-3 text-sm text-slate-300 ">Gists</td>
<td class="whitespace-nowrap px-2 py-2 text-sm font-medium text-slate-300">{{ .countGists }}</td>
</tr>
<tr>
<td class="whitespace-nowrap py-2 pr-3 text-sm text-slate-300 ">SSH keys</td>
<td class="whitespace-nowrap px-2 py-2 text-sm font-medium text-slate-300">{{ .countKeys }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{{ template "admin_footer" .}}
{{ template "footer" .}}

35
templates/pages/admin_users.html vendored Normal file
View File

@ -0,0 +1,35 @@
{{ template "header" .}}
{{ template "admin_header" .}}
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8 bg-gray-800 rounded-md border border-gray-700">
<table class="min-w-full divide-y divide-gray-500">
<thead>
<tr>
<th scope="col" class="whitespace-nowrap py-3.5 pl-4 pr-3 text-left text-sm font-bold text-slate-300 sm:pl-0">ID</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300">Username</th>
<th scope="col" class="whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-slate-300">Created</th>
<th scope="col" class="relative whitespace-nowrap py-3.5 pl-3 pr-4 sm:pr-0">
<span class="sr-only">Delete</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-500">
{{ range $user := .data }}
<tr>
<td class="whitespace-nowrap py-2 pl-4 pr-3 text-sm text-slate-300 sm:pl-0">{{ $user.ID }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><a href="/{{ $user.Username }}">{{ $user.Username }}</a></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-300"><span class="moment-timestamp-date">{{ $user.CreatedAt }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="/admin/users/{{ $user.ID }}/delete" method="POST" onsubmit="return confirm('Do you want to delete this user ?')">
{{ $.csrfHtml }}
<button type="submit" class="text-rose-500 hover:text-rose-600">Delete</button>
</form>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ template "admin_footer" .}}
{{ template "footer" .}}

109
templates/pages/all.html vendored Normal file
View File

@ -0,0 +1,109 @@
{{ template "header" .}}
<div class="py-10">
<header class="pb-4 flex ">
<div class="flex-auto">
<h1 class="text-2xl font-bold leading-tight">All gists {{if .fromUser}} from {{.fromUser}} {{end}}</h1>
</div>
<div class="float-right">
<div class="relative inline-block text-left">
<div>
<button type="button" class="inline-flex text-slate-300 rounded border border-gray-600 bg-gray-800 px-2.5 py-2 text-xs font-medium text-white shadow-sm hover:bg-gray-700 hover:border-gray-500 hover:text-slate-300 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500 leading-3" id="sort-gists-button">
<span class="text-gray-300">Sort : <span class="text-slate-300">{{.order}} {{.sort}}</span></span>
<svg class="-mr-1 ml-2 h-3 w-3" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd" />
</svg>
</button>
</div>
<div id="sort-gists-dropdown" class="hidden absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-700 rounded-md rounded border border-gray-600 bg-gray-800 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
<div class="" role="none">
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=created&order=desc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500 hover:rounded-t-md" role="menuitem">
Recently created
</a>
</div>
<div class="" role="none">
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=created&order=asc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500" role="menuitem">
Least recently created
</a>
</div><div class="" role="none">
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=updated&order=desc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500" role="menuitem">
Recently updated
</a>
</div>
<div class="" role="none">
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=updated&order=asc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500 hover:rounded-b-md" role="menuitem">
Least recently updated
</a>
</div>
</div>
</div>
</div>
</header>
<main>
<div>
{{ if ne (len .gists) 0 }}
{{ range $gist := .gists }}
<div class="mb-8">
<div class="flex">
<h4 class="text-md leading-tight break-all py-1 flex-auto">
<a href="/{{ $gist.User.Username }}">{{ $gist.User.Username }}</a> <span class="text-slate-300">/</span> <a class="font-bold" href="/{{ $gist.User.Username }}/{{ $gist.Uuid }}">{{ $gist.Title }}</a>
</h4>
<div class="flex space-x-4">
<div class="flex items-center float-right text-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-1 inline-flex">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
<span>{{ $gist.NbLikes }} likes</span>
</div>
<div class="flex items-center float-right text-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-1 inline-flex">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.25 9.75L16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0020.25 18V6A2.25 2.25 0 0018 3.75H6A2.25 2.25 0 003.75 6v12A2.25 2.25 0 006 20.25z" />
</svg>
<span>{{ $gist.NbFiles }} files</span>
</div>
</div>
</div>
<h5 class="text-sm text-slate-500 pb-1">Last active <span class="moment-timestamp">{{ $gist.UpdatedAt }}</span>
{{ if $gist.Private }} • <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-700 text-slate-300"> Unlisted </span>{{ end }}</h5>
<h5 class="text-xs text-slate-300 py-1">{{ $gist.Description }}</h5>
<a href="/{{ $gist.User.Username }}/{{ $gist.Uuid }}" class="hover:text-slate-300">
<div class="rounded-md border border-1 border-gray-700 overflow-auto hover:border-primary-600">
<div class="code overflow-auto">
{{ if isMarkdown $gist.PreviewFilename }}
<div class="markdown markdown-body p-8">{{ $gist.Preview }}</div>
{{ else }}
<table class="table-code w-full whitespace-pre" data-filename="{{ $gist.PreviewFilename }}" style="font-size: 0.8em; border-spacing: 0; border-collapse: collapse;">
<tbody>
{{ $ii := "1" }}
{{ $i := toInt $ii }}
{{ range $line := lines $gist.Preview }}
<tr>
<td class="select-none line-num px-4">{{$i}}</td>
<td class="line-code">{{ $line }}</td>
</tr>
{{ $i = inc $i }}
{{ end }}
</tbody>
</table>
{{ end }}
</div>
</div>
</a>
</div>
{{ end }}
{{ template "pagination" . }}
{{ else }}
<div class="text-center">
<svg xmlns="http://www.w3.org/2000/svg" class="mx-auto h-12 w-12 text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M14 10l-2 1m0 0l-2-1m2 1v2.5M20 7l-2 1m2-1l-2-1m2 1v2.5M14 4l-2-1-2 1M4 7l2-1M4 7l2 1M4 7v2.5M12 21l-2-1m2 1l2-1m-2 1v-2.5M6 18l-2-1v-2.5M18 18l2-1v-2.5" />
</svg>
<h3 class="mt-2 text-sm font-medium text-slate-300">No gists</h3>
</div>
{{ end }}
</div>
</main>
</div>
{{ template "footer" .}}

58
templates/pages/auth_form.html vendored Normal file
View File

@ -0,0 +1,58 @@
{{ template "header" .}}
<div class="py-10">
<header>
<h1 class="text-2xl font-bold leading-tight text-slate-300">
{{ .title }}
</h1>
</header>
<main class="mt-4">
{{ if and .signupDisabled (ne .title "Login") }}
<p class="italic">Administrator has disabled signing up</p>
{{ else }}
<div class="sm:col-span-6">
<div class="mt-8 sm:w-full sm:max-w-md">
<div class="bg-gray-900 rounded-md border border-1 border-gray-700 py-8 px-4 shadow sm:rounded-lg sm:px-10">
<form class="space-y-6" action="#" method="post">
<div>
<label for="username" class="block text-sm font-medium text-slate-300"> Username </label>
<div class="mt-1">
<input id="username" name="username" type="text" required class="bg-gray-800 appearance-none block w-full px-3 py-2 border border-gray-700 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm">
</div>
</div>
<div class="mt-8">
<label for="password" class="block text-sm font-medium text-slate-300"> Password </label>
<div class="mt-1">
<input id="password" name="password" type="password" autocomplete="current-password" required class="bg-gray-800 appearance-none block w-full px-3 py-2 border border-gray-700 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm">
</div>
</div>
{{ if eq .title "Login" }}
<div class="flex">
<div class="flex-auto">
<button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">Login</button>
</div>
{{ if not .signupDisabled }}
<span class="float-right text-sm py-2 underline"><a href="/register">Register instead →</a></span>
{{ end }}
</div>
{{ else }}
<div class="flex">
<div class="flex-auto">
<button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">Register</button>
</div>
<span class="float-right text-sm py-2 underline"><a href="/login">Login instead →</a></span>
</div>
{{ end }}
{{ .csrfHtml }}
</form>
</div>
</div>
</div>
{{ end }}
</main>
</div>
{{ template "footer" .}}

49
templates/pages/create.html vendored Normal file
View File

@ -0,0 +1,49 @@
{{ template "header" .}}
<div class="py-10">
<header>
<h1 class="text-2xl font-bold leading-tight text-slate-300">
New Gist
</h1>
</header>
<main class="mt-4">
<form id="create" class="space-y-4" method="post" action="/">
<div class="grid grid-cols-12 gap-x-4">
<div class="col-span-4">
<div class="mt-1">
<input type="text" placeholder="Title" name="title" id="title" class="bg-black shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-700 rounded-md">
</div>
</div>
<div class="col-span-8">
<div class="mt-1">
<input type="text" placeholder="Description" name="description" id="description" class="bg-black shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-700 rounded-md">
</div>
</div>
</div>
<div id="editors" class="space-y-4">
<div class="rounded-md border border-1 border-gray-700 editor">
<div class="border-b-1 border-gray-700 bg-gray-800 my-auto">
<p class="mx-2 my-2 inline-flex">
<input type="text" name="name" placeholder="Filename with extension" style="line-height: 0.05em" class="form-filename bg-gray-900 shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-700 rounded-md">
</p>
</div>
<input type="hidden" value="" name="content" class="form-filecontent">
</div>
</div>
<div class="flex">
<button type="button" id="add-file" class="inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">Add file</button>
<button type="submit" name="private" value="1" class="ml-auto inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">Create unlisted gist</button>
<button type="submit" name="private" value="0" class="ml-2 inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">Create public gist</button>
</div>
{{ .csrfHtml }}
</form>
</main>
</div>
<script type="module" src="http://localhost:3000/editor.js"></script>
{{ template "footer" .}}

57
templates/pages/edit.html vendored Normal file
View File

@ -0,0 +1,57 @@
{{ template "header" .}}
<div class="py-10">
<header>
<h1 class="text-2xl font-bold leading-tight text-slate-300">
Editing {{ .gist.Title }}
</h1>
</header>
<main class="mt-4">
<form id="create" class="space-y-4" method="post" action="/{{ .gist.User.Username }}/{{ .gist.Uuid }}/edit">
<div class="grid grid-cols-12 gap-x-4">
<div class="sm:col-span-4">
<div class="mt-1">
<input type="text" value="{{ .gist.Title }}" placeholder="Title" name="title" id="title" class="bg-black shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-700 rounded-md">
</div>
</div>
<div class="sm:col-span-8">
<div class="mt-1">
<input type="text" value="{{ .gist.Description }}" placeholder="Description" name="description" id="description" class="bg-black shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-700 rounded-md">
</div>
</div>
</div>
<div id="editors" class="space-y-4">
{{ range $filename, $content := .files }}
<div class="rounded-md border border-1 border-gray-700 editor">
<div class="border-b-1 border-gray-700 bg-gray-800 my-auto">
<p class="mx-2 my-2 inline-flex">
<input type="text" value="{{ $filename }}" name="name" placeholder="Filename with extension" style="line-height: 0.05em; z-index: 99999" class="form-filename bg-gray-900 shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-700 rounded-l-md">
<button style="line-height: 0.05em" class="delete-file -ml-px relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-700 text-sm font-medium rounded-r-md text-slate-300 bg-gray-800 hover:bg-gray-900 focus:outline-none" type="button">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
</button>
</p>
</div>
<input type="hidden" value="{{ $content }}" name="content" class="form-filecontent">
</div>
{{ end }}
</div>
<div class="flex">
<button type="button" id="add-file" class="inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">Add file</button>
<a href="/{{ .gist.User.Username }}/{{ .gist.Uuid }}" type="submit" name="private" value="1" class="ml-auto inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 text-rose-400 hover:text-rose-400">Cancel</a>
<button type="submit" name="private" value="0" class="ml-2 inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">Save</button>
</div>
{{ .csrfHtml }}
</form>
</main>
</div>
<script type="module" src="http://localhost:3000/editor.js"></script>
{{ template "footer" .}}

14
templates/pages/error.html vendored Normal file
View File

@ -0,0 +1,14 @@
{{ template "header" .}}
<div class="mt-4">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-12 w-12 text-slate-400">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
</svg>
<h1 class="mt-2 text-3xl font-medium text-slate-300">Error {{ .error.Code }}</h1>
<h3 class="mt-2 text-md font-medium text-slate-300">{{ httpStatusText .error.Code }}</h3>
{{ if lt .error.Code 500 }}
<p class="mt-2 text-sm font-medium text-slate-300">{{ .error.Message }}</p>
{{ end }}
</div>
{{ template "footer" .}}

45
templates/pages/gist.html vendored Normal file
View File

@ -0,0 +1,45 @@
{{ template "header" .}}
{{ template "gist_header" .}}
{{ if .files }}
<div class="grid gap-y-4">
{{ range $filename, $content := .files }}
<div class="rounded-md border border-1 border-gray-700 overflow-auto">
<div class="border-b-1 border-gray-700 bg-gray-800 my-auto block">
<div class="ml-4 py-1.5 flex">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 flex text-slate-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
<span class="flex-auto ml-2 text-sm text-slate-300 filename" id="file-{{ slug $filename }}"><a href="#file-{{ slug $filename }}">{{ $filename }}</a></span>
<button class="float-right mx-2 px-2.5 py-0.5 leading-4 rounded-full text-xs font-medium bg-gray-600 border border-gray-500 hover:bg-gray-700 hover:text-slate-300 select-none copy-gist-btn"> Copy </button>
<a href="/{{ $.gist.User.Username }}/{{ $.gist.Uuid }}/raw/{{ $.commit }}/{{$filename}}" class="float-right mr-2 px-2.5 py-0.5 leading-4 rounded-full text-xs font-medium bg-gray-600 border border-gray-500 hover:bg-gray-700 hover:text-slate-300 select-none"> Raw </a>
<div class="hidden gist-content">{{ $content }}</div>
</div>
</div>
<div class="code overflow-auto">
{{ if isMarkdown $filename }}
<div class="markdown markdown-body p-8">{{ $content }}</div>
{{ else }}
{{ $fileslug := slug $filename }}
<table class="table-code w-full whitespace-pre" data-filename-slug="{{ $fileslug }}" data-filename="{{ $filename }}" style="font-size: 0.8em; border-spacing: 0; border-collapse: collapse;">
<tbody>
{{ $ii := "1" }}
{{ $i := toInt $ii }}
{{ range $line := lines $content }}<tr><td id="file-{{ $fileslug }}-{{$i}}" class="select-none line-num px-4">{{$i}}</td><td class="line-code">{{ $line }}</td></tr>{{ $i = inc $i }}{{ end }}
</tbody>
</table>
{{ end }}
</div>
</div>
{{ end }}
</div>
{{ else }}
<div class="text-center">
<svg xmlns="http://www.w3.org/2000/svg" class="mx-auto h-12 w-12 text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M14 10l-2 1m0 0l-2-1m2 1v2.5M20 7l-2 1m2-1l-2-1m2 1v2.5M14 4l-2-1-2 1M4 7l2-1M4 7l2 1M4 7v2.5M12 21l-2-1m2 1l2-1m-2 1v-2.5M6 18l-2-1v-2.5M18 18l2-1v-2.5" />
</svg>
<h3 class="mt-2 text-sm font-medium text-slate-300">No content</h3>
</div>
{{ end }}
{{ template "gist_footer" .}}
{{ template "footer" .}}

27
templates/pages/likes.html vendored Normal file
View File

@ -0,0 +1,27 @@
{{ template "header" .}}
{{ template "gist_header" .}}
{{ if ne (len .likers) 0 }}
<h3 class="text-xl font-bold leading-tight break-all py-2">Likes</h3>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-5">
{{ range $user := .likers }}
<div class="relative flex items-center space-x-3 rounded-lg border border-gray-600 bg-gray-800 px-6 py-5 shadow-sm focus-within:ring-1 focus-within:border-primary-500 focus-within:ring-primary-500 hover:border-gray-400">
<div class="min-w-0 flex-1">
<a href="/{{ $user.Username }}" class="focus:outline-none">
<span class="absolute inset-0" aria-hidden="true"></span>
<p class="text-sm font-medium text-slate-300">{{ $user.Username }}</p>
</a>
</div>
</div>
{{ end }}
</div>
{{ else }}
<div class="text-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="mx-auto h-12 w-12 text-slate-400">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
</svg>
<h3 class="mt-2 text-sm font-medium text-slate-300">No likes yet</h3>
</div>
{{ end }}
{{ template "gist_footer" .}}
{{ template "footer" .}}

110
templates/pages/revisions.html vendored Normal file
View File

@ -0,0 +1,110 @@
{{ template "header" .}}
{{ template "gist_header" .}}
{{ if ne (len .commits) 0 }}
<div>
{{ range $commit := .commits }}
<div class="pb-8">
<div class="flex">
<h3 class="text-sm py-2 flex-auto"><svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 mr-1 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
</svg><span class="font-bold">{{ $commit.Author }}</span> revised this gist <span class="moment-timestamp font-bold">{{ $commit.Timestamp }}</span>. <a class="underline" href="/{{ $.gist.User.Username }}/{{ $.gist.Uuid }}/rev/{{ $commit.Hash }}">Go to revision</a></h3>
{{ if ne $commit.Changed "" }}
<p class="text-sm float-right py-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 inline-flex">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
</svg>
{{ $commit.Changed }}
{{ end }}
</p>
</div>
<div class="grid gap-y-4">
{{ if ne (len $commit.Files) 0 }}
{{ range $file := $commit.Files }}
<div class="rounded-md border border-1 border-gray-700 overflow-auto">
<div class="border-b-1 border-gray-700 bg-gray-800 my-auto">
<p class="ml-4 mt-2 inline-flex">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 flex text-slate-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
{{ if eq $file.Filename $file.OldFilename }}
<span class="flex text-sm ml-2 text-slate-300">{{ $file.Filename }}</span>
{{ else }}
{{ if eq $file.OldFilename "/dev/null" }}
<span class="flex text-sm ml-2 text-slate-300">{{ $file.Filename }}<span class="italic text-gray-400 ml-1">(file created)</span></span>
{{ else if eq $file.Filename "/dev/null" }}
<span class="flex text-sm ml-2 text-slate-300">{{ $file.OldFilename }} <span class="italic text-gray-400 ml-1">(file deleted)</span></span>
{{ else }}
<span class="flex text-sm ml-2 text-slate-300">{{ $file.OldFilename }} <span class="italic text-gray-400 mx-1">renamed to</span> {{ $file.Filename }}</span>
{{ end }}
{{ end }}
</p>
</div>
<div class="code overflow-auto">
{{ if eq $file.Content "" }}
<p class="m-2 ml-4 text-sm">
File renamed without changes.
</p>
{{ else }}
<table class="table-code w-full whitespace-pre" data-filename="{{ $file.Filename }}" style="font-size: 0.8em; border-spacing: 0">
<tbody>
{{ $left := 0 }}
{{ $right := 0 }}
{{ range $line := split $file.Content "\n" }}
{{ if ne $line "" }}{{ if ne (index $line 0) 92 }}
{{ if eq (index $line 0) 64 }}
{{ $left = toInt (index (splitGit (index (split $line "-") 1)) 0) }}
{{ $right = toInt (index (splitGit (index (split $line "+") 1)) 0) }}
{{ end }}
<tr class="{{ if eq (index $line 0) 64 }}gray-diff{{ end }}{{ if eq (index $line 0) 43 }}green-diff{{ end }}{{ if eq (index $line 0) 45 }}red-diff{{ end }}" >
{{ if eq (index $line 0) 64 }}
<td colspan="2" class="select-none py-3"></td>
{{ else }}
{{ if eq (index $line 0) 43 }}
<td class="select-none line-num px-2"></td>
<td class="select-none line-num px-2">{{ $right }}</td>
{{ $right = inc $right }}
{{ else if eq (index $line 0) 45 }}
<td class="select-none line-num px-2">{{ $left }}</td>
<td class="select-none line-num px-2"></td>
{{ $left = inc $left }}
{{ else if eq (index $line 0) 32 }}
<td class="select-none line-num px-2">{{ $left }}</td>
<td class="select-none line-num px-2">{{ $right }}</td>
{{ $left = inc $left }}
{{ $right = inc $right }}
{{ end }}
{{ end }}
<td class="select-none" style="width: 2%;">{{ if ne (index $line 0) 64 }}{{ slice $line 0 1 }}{{ end }}</td>
<td>{{ if ne (index $line 0) 64 }}{{ slice $line 1 }}{{ else }}{{ $line }}{{ end }}</td>
</tr>
{{end}}
{{end}}{{end}}
</tbody>
</table>
{{ end }}
</div>
</div>
{{end}}
{{else}}
<p class="text-left text-sm text-slate-300 italic">No changes</p>
{{end}}
</div>
</div>
{{end}}
</div>
<div class="flex justify-center space-x-2">
{{ template "pagination" . }}
</div>
{{ else }}
<div class="text-center">
<svg xmlns="http://www.w3.org/2000/svg" class="mx-auto h-12 w-12 text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M14 10l-2 1m0 0l-2-1m2 1v2.5M20 7l-2 1m2-1l-2-1m2 1v2.5M14 4l-2-1-2 1M4 7l2-1M4 7l2 1M4 7v2.5M12 21l-2-1m2 1l2-1m-2 1v-2.5M6 18l-2-1v-2.5M18 18l2-1v-2.5" />
</svg>
<h3 class="mt-2 text-sm font-medium text-slate-300">No revisions to show</h3>
</div>
{{ end }}
{{ template "gist_footer" .}}
{{ template "footer" .}}

73
templates/pages/ssh_keys.html vendored Normal file
View File

@ -0,0 +1,73 @@
{{ template "header" .}}
<div class="py-10">
<header class="pb-4">
<div>
<h1 class="text-2xl font-bold leading-tight">SSH Keys</h1>
<p class="text-sm text-gray-400 italic">Used only to pull/push gists using Git via SSH</p>
</div>
</header>
<main>
<div >
<div class="sm:grid grid-cols-2 gap-x-4 md:gap-x-16">
<div class="w-full">
<div class="bg-gray-900 rounded-md border border-1 border-gray-700 py-8 px-4 shadow sm:rounded-lg sm:px-10">
<h2 class="text-md font-bold text-slate-300 mb-4">
Add SSH Key
</h2>
<form class="space-y-6" action="#" method="post">
<div>
<label for="title" class="block text-sm font-medium text-slate-300"> Title </label>
<div class="mt-1">
<input id="title" name="title" type="text" required autocomplete="off" class="bg-gray-800 appearance-none block w-full px-3 py-2 border border-gray-700 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm">
</div>
</div>
<div class="mt-8">
<label for="sshkey" class="block text-sm font-medium text-slate-300"> Key </label>
<div class="mt-1">
<textarea id="sshkey" required autocomplete="off" name="content" class="bg-gray-800 appearance-none block w-full px-3 py-2 border border-gray-700 rounded-md shadow-sm placeholder-gray-400 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm"></textarea>
</div>
</div>
<button type="submit" class="inline-flex items-center px-4 py-2 border border-transparent border-gray-700 text-sm font-medium rounded-md shadow-sm text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500">Add key</button>
{{ .csrfHtml }}
</form>
</div>
</div>
<div>
<div class="mt-6 flow-root">
<ul role="list" class="-my-5 divide-y divide-gray-700 list-none">
{{ if .sshKeys }}
{{ range $key := .sshKeys }}
<li class="py-5">
<div class="inline-flex">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-12 h-12 mr-4">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z" />
</svg>
<div>
<h3 class="text-sm font-semibold text-slate-300">{{ .Title }}</h3>
<p class="mt-1 text-xs text-slate-400 line-clamp-2 code" style="overflow-wrap: anywhere">SHA256:{{.SHA}}</p>
<p class="text-xs text-gray-500 line-clamp-2">Added <span class="moment-timestamp-date">{{ .CreatedAt }}</span></p>
{{ if eq .LastUsedAt 0 }}
<p class="text-xs text-gray-500 line-clamp-2">Never used</p>
{{ else }}
<p class="text-xs text-gray-500 line-clamp-2">Last used <span class="moment-timestamp">{{ .LastUsedAt }}</span></p>
{{ end }}
</div>
<form action="/ssh-keys/{{.ID}}" method="post" class="inline-block" onsubmit="return confirm('Confirm deletion of SSH key')">
<input type="hidden" name="_method" value="DELETE">
{{ $.csrfHtml }}
<button type="submit" class="align-middle items-center leading-2 ml-2 px-3 py-1 border border-transparent border-gray-700 text-xs font-medium rounded-md shadow-sm text-white bg-rose-600 hover:bg-rose-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500">Delete</button>
</form>
</div>
</li>
{{ end }}
{{ end }}
</ul>
</div>
</div>
</div>
</div>
</main>
</div>
{{ template "footer" .}}