Fix human date on iOS devices (#510)

This commit is contained in:
Thomas Miceli
2025-09-21 04:31:58 +02:00
committed by GitHub
parent c02bf97b63
commit 4106956f6d
14 changed files with 24 additions and 47 deletions

View File

@@ -15,6 +15,7 @@ import (
"strings"
"time"
"github.com/dustin/go-humanize"
"github.com/labstack/echo/v4"
"github.com/rs/zerolog/log"
"github.com/thomiceli/opengist/internal/config"
@@ -175,6 +176,16 @@ func (s *Server) setFuncMap() {
h, _ := strconv.ParseUint(strings.TrimPrefix(hex, "#"), 16, 32)
return fmt.Sprintf("%d, %d, %d,", (h>>16)&0xFF, (h>>8)&0xFF, h&0xFF)
},
"humanTimeDiff": func(t int64) string {
return humanize.Time(time.Unix(t, 0))
},
"humanTimeDiffStr": func(timestamp string) string {
t, _ := strconv.ParseInt(timestamp, 10, 64)
return humanize.Time(time.Unix(t, 0))
},
"humanDate": func(t int64) string {
return time.Unix(t, 0).Format("02/01/2006 15:04")
},
}
t := template.Must(template.New("t").Funcs(fm).ParseFS(templates.Files, "*/*.html"))

8
package-lock.json generated
View File

@@ -17,7 +17,6 @@
"autoprefixer": "^10.4.14",
"codemirror": "^6.0.1",
"cssnano": "^5.1.15",
"dayjs": "^1.11.9",
"github-markdown-css": "^5.5.0",
"highlight.js": "^11.11.1",
"jdenticon": "^3.3.0",
@@ -1872,13 +1871,6 @@
"node": ">=8.0.0"
}
},
"node_modules/dayjs": {
"version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
"integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==",
"dev": true,
"license": "MIT"
},
"node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",

View File

@@ -21,7 +21,6 @@
"autoprefixer": "^10.4.14",
"codemirror": "^6.0.1",
"cssnano": "^5.1.15",
"dayjs": "^1.11.9",
"github-markdown-css": "^5.5.0",
"highlight.js": "^11.11.1",
"jdenticon": "^3.3.0",

View File

@@ -1,23 +1,8 @@
import './style.scss';
import './favicon-32.png';
import './opengist.svg';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/cs';
import 'dayjs/locale/de';
import 'dayjs/locale/es';
import 'dayjs/locale/fr';
import 'dayjs/locale/hu';
import 'dayjs/locale/pt';
import 'dayjs/locale/ru';
import 'dayjs/locale/zh';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import jdenticon from 'jdenticon/standalone';
dayjs.extend(relativeTime);
dayjs.extend(localizedFormat);
dayjs.locale(window.opengist_locale || 'en');
jdenticon.update("[data-jdenticon-value]")
document.addEventListener('DOMContentLoaded', () => {
@@ -55,23 +40,13 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('user-menu').classList.toggle('hidden');
})
document.querySelectorAll('.moment-timestamp').forEach((e: HTMLElement) => {
e.title = dayjs.unix(parseInt(e.innerHTML)).format('LLLL');
e.innerHTML = dayjs.unix(parseInt(e.innerHTML)).fromNow();
});
document.querySelectorAll('.moment-timestamp-date').forEach((e: HTMLElement) => {
e.innerHTML = dayjs.unix(parseInt(e.innerHTML)).format('DD/MM/YYYY HH:mm');
});
document.querySelectorAll('form').forEach((form: HTMLFormElement) => {
form.onsubmit = () => {
form.querySelectorAll('input[type=datetime-local]').forEach((input: HTMLInputElement) => {
console.log(dayjs(input.value).unix());
const hiddenInput = document.createElement('input');
hiddenInput.type = 'hidden';
hiddenInput.name = 'expiredAtUnix'
hiddenInput.value = dayjs(input.value).unix().toString();
hiddenInput.value = Math.floor(new Date(input.value).getTime() / 1000).toString();
form.appendChild(hiddenInput);
});
return true;

View File

@@ -91,7 +91,7 @@
{{ if .gist.Forked }}
<p class="mt-1 max-w-2xl text-sm text-slate-500">{{ .locale.Tr "gist.header.forked-from" }} <a href="{{ $.c.ExternalUrl }}/{{ .gist.Forked.User.Username }}/{{ .gist.Forked.Identifier }}">{{ .gist.Forked.User.Username }}/{{ .gist.Forked.Title }}</a></p>
{{ end }}
<p class="mt-1 max-w-2xl text-sm text-slate-500">{{ .locale.Tr "gist.header.last-active" }} <span class="moment-timestamp"> {{ .gist.UpdatedAt }} </span>
<p class="mt-1 max-w-2xl text-sm text-slate-500">{{ .locale.Tr "gist.header.last-active" }} <span> {{ .gist.UpdatedAt | humanTimeDiff }} </span>
{{ if .gist.Private }} • <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-700 text-slate-700 dark:text-slate-300"> {{ visibilityStr .gist.Private false }} </span>{{ end }}
</p>
<p class="mt-1 text-sm max-w-2xl text-slate-600 dark:text-slate-400">{{ .gist.Description }}</p>

View File

@@ -26,7 +26,7 @@
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300">{{ $gist.Private }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300">{{ $gist.NbFiles }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300">{{ $gist.NbLikes }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><span class="moment-timestamp-date">{{ $gist.CreatedAt }}</span></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><span>{{ $gist.CreatedAt | humanDate }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/gists/{{ $gist.ID }}/delete" method="POST">
{{ $.csrfHtml }}

View File

@@ -51,7 +51,7 @@
{{ end }}
</td>
<td class="whitespace-nowrap py-2 px-2 text-sm">{{ $invitation.NbUsed }}/{{ $invitation.NbMax }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm"><span class="moment-timestamp-date">{{ $invitation.ExpiresAt }}</span></td>
<td class="whitespace-nowrap px-2 py-2 text-sm"><span>{{ $invitation.ExpiresAt | humanDate }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/invitations/{{ $invitation.ID }}/delete" method="POST">
{{ $.csrfHtml }}

View File

@@ -18,7 +18,7 @@
<tr>
<td class="whitespace-nowrap py-2 pl-4 pr-3 text-sm text-slate-700 dark:text-slate-300 sm:pl-0">{{ $user.ID }}</td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><a href="{{ $.c.ExternalUrl }}/{{ $user.Username }}">{{ $user.Username }}</a></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><span class="moment-timestamp-date">{{ $user.CreatedAt }}</span></td>
<td class="whitespace-nowrap px-2 py-2 text-sm text-slate-700 dark:text-slate-300"><span>{{ $user.CreatedAt | humanDate }}</span></td>
<td class="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<form action="{{ $.c.ExternalUrl }}/admin-panel/users/{{ $user.ID }}/delete" method="POST">
{{ $.csrfHtml }}

View File

@@ -18,7 +18,7 @@
</div>
<div>
<h1 class="text-2xl font-bold leading-tight">{{.fromUser.Username}}</h1>
<p class="text-sm text-slate-500">{{ .locale.Tr "gist.list.joined" }} <span class="moment-timestamp">{{.fromUser.CreatedAt}}</span></p>
<p class="text-sm text-slate-500">{{ .locale.Tr "gist.list.joined" }} <span>{{.fromUser.CreatedAt | humanTimeDiff}}</span></p>
</div>
</div>
{{ else }}

View File

@@ -16,7 +16,7 @@
</a>
<div>
<a href="{{ $.c.ExternalUrl }}/{{ $gist.User.Username }}" class="text-sm font-medium text-slate-700 dark:text-slate-300">{{ $gist.User.Username }}</a>
<p class="text-sm text-slate-500">{{ $.locale.Tr "gist.list.forked" }} <span class="moment-timestamp">{{ $gist.CreatedAt }}</span></p>
<p class="text-sm text-slate-500">{{ $.locale.Tr "gist.list.forked" }} <span>{{ $gist.CreatedAt | humanTimeDiff }}</span></p>
</div>
<div class="ml-auto">
<a class="ml-auto text-slate-700 dark:text-slate-300 relative inline-flex items-center space-x-2 rounded-md border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 px-2 py-1.5 text-xs font-medium text-slate-700 dark:text-slate-300 hover:bg-gray-200 dark:hover:bg-gray-700 hover:border-gray-500 hover:text-slate-700 dark:hover:text-slate-300 focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500 leading-3" href="{{ $.c.ExternalUrl }}/{{ $gist.User.Username }}/{{ $gist.Identifier }}">

View File

@@ -16,7 +16,7 @@
{{ else }}
<svg class="h-5 w-5 rounded-full inline" data-jdenticon-value="{{ $commit.AuthorName }}" width="20" height="20"></svg>
{{ end }}
<span class="font-bold">{{if $user}}<a href="{{ $.c.ExternalUrl }}/{{$user.Username}}" class="text-slate-300 hover:text-slate-300 hover:underline">{{ $commit.AuthorName }}</a>{{else}}{{ $commit.AuthorName }}{{end}}</span> {{ $.locale.Tr "gist.revision.revised" }} <span class="moment-timestamp font-bold">{{ $commit.Timestamp }}</span>. <a href="{{ $.c.ExternalUrl }}/{{ $.gist.User.Username }}/{{ $.gist.Identifier }}/rev/{{ $commit.Hash }}">{{ $.locale.Tr "gist.revision.go-to-revision" }}</a></h3>
<span class="font-bold">{{if $user}}<a href="{{ $.c.ExternalUrl }}/{{$user.Username}}" class="text-slate-300 hover:text-slate-300 hover:underline">{{ $commit.AuthorName }}</a>{{else}}{{ $commit.AuthorName }}{{end}}</span> {{ $.locale.Tr "gist.revision.revised" }} <span class="font-bold">{{ $commit.Timestamp | humanTimeDiffStr }}</span>. <a href="{{ $.c.ExternalUrl }}/{{ $.gist.User.Username }}/{{ $.gist.Identifier }}/rev/{{ $commit.Hash }}">{{ $.locale.Tr "gist.revision.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">

View File

@@ -63,11 +63,11 @@
</svg>
<div>
<h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">{{ .Name }}</h3>
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "auth.mfa.passkey-added-at" }} <span class="moment-timestamp-date">{{ .CreatedAt }}</span></p>
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "auth.mfa.passkey-added-at" }} <span>{{ .CreatedAt | humanDate }}</span></p>
{{ if eq .LastUsedAt 0 }}
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "auth.mfa.passkey-never-used" }}</p>
{{ else }}
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "auth.mfa.passkey-last-used" }} <span class="moment-timestamp">{{ .LastUsedAt }}</span></p>
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "auth.mfa.passkey-last-used" }} <span>{{ .LastUsedAt | humanTimeDiff }}</span></p>
{{ end }}
</div>
<form action="{{ $.c.ExternalUrl }}/settings/passkeys/{{.ID}}" method="post" class="inline-block">

View File

@@ -42,11 +42,11 @@
<div>
<h3 class="text-sm font-semibold text-slate-700 dark:text-slate-300">{{ .Title }}</h3>
<p class="mt-1 text-xs text-slate-600 dark:text-slate-400 line-clamp-2 code" style="overflow-wrap: anywhere">SHA256:{{.SHA}}</p>
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "settings.ssh-key-added-at" }} <span class="moment-timestamp-date">{{ .CreatedAt }}</span></p>
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "settings.ssh-key-added-at" }} <span>{{ .CreatedAt | humanDate }}</span></p>
{{ if eq .LastUsedAt 0 }}
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "settings.ssh-key-never-used" }}</p>
{{ else }}
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "settings.ssh-key-last-used" }} <span class="moment-timestamp">{{ .LastUsedAt }}</span></p>
<p class="text-xs text-gray-500 line-clamp-2">{{ $.locale.Tr "settings.ssh-key-last-used" }} <span>{{ .LastUsedAt | humanTimeDiff }}</span></p>
{{ end }}
</div>
<form action="{{ $.c.ExternalUrl }}/settings/ssh-keys/{{.ID}}" method="post" class="inline-block">

View File

@@ -39,7 +39,7 @@
</div>
</div>
<h5 class="text-sm text-slate-500 pb-1">{{ .locale.Tr "gist.list.last-active" }} <span class="moment-timestamp">{{ .gist.UpdatedAt }}</span>
<h5 class="text-sm text-slate-500 pb-1">{{ .locale.Tr "gist.list.last-active" }} <span>{{ .gist.UpdatedAt | humanTimeDiff }}</span>
{{ if .gist.Forked }} • {{ .locale.Tr "gist.list.forked-from" }} <a href="{{ .c.ExternalUrl }}/{{ .gist.Forked.User.Username }}/{{ .gist.Forked.Identifier }}">{{ .gist.Forked.User.Username }}/{{ .gist.Forked.Title }}</a> {{ end }}
{{ if .gist.Private }} • <span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-700 text-slate-700 dark:text-slate-300"> {{ visibilityStr .gist.Private false }} </span>{{ end }}</h5>
<div class="flex items-center gap-2 mb-2">