summaryrefslogtreecommitdiffstats
path: root/templates/base
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-10-11 10:27:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-10-11 10:27:00 +0000
commit65aa53fc52ff15efe54df4147564828d535837f8 (patch)
tree31c51dad04fdcca80e6d3043c8bd49d2f1a51f83 /templates/base
parentInitial commit. (diff)
downloadforgejo-65aa53fc52ff15efe54df4147564828d535837f8.tar.xz
forgejo-65aa53fc52ff15efe54df4147564828d535837f8.zip
Adding upstream version 8.0.3.HEADupstream/8.0.3upstreamdebian
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'templates/base')
-rw-r--r--templates/base/alert.tmpl20
-rw-r--r--templates/base/alert_details.tmpl7
-rw-r--r--templates/base/disable_form_autofill.tmpl31
-rw-r--r--templates/base/footer.tmpl20
-rw-r--r--templates/base/footer_content.tmpl32
-rw-r--r--templates/base/head.tmpl50
-rw-r--r--templates/base/head_navbar.tmpl205
-rw-r--r--templates/base/head_opengraph.tmpl47
-rw-r--r--templates/base/head_script.tmpl50
-rw-r--r--templates/base/head_style.tmpl2
-rw-r--r--templates/base/modal_actions_confirm.tmpl35
-rw-r--r--templates/base/paginate.tmpl34
12 files changed, 533 insertions, 0 deletions
diff --git a/templates/base/alert.tmpl b/templates/base/alert.tmpl
new file mode 100644
index 00000000..760d3bfa
--- /dev/null
+++ b/templates/base/alert.tmpl
@@ -0,0 +1,20 @@
+{{if .Flash.ErrorMsg}}
+ <div class="ui negative message flash-message flash-error">
+ <p>{{.Flash.ErrorMsg | SanitizeHTML}}</p>
+ </div>
+{{end}}
+{{if .Flash.SuccessMsg}}
+ <div class="ui positive message flash-message flash-success">
+ <p>{{.Flash.SuccessMsg | SanitizeHTML}}</p>
+ </div>
+{{end}}
+{{if .Flash.InfoMsg}}
+ <div class="ui info message flash-message flash-info">
+ <p>{{.Flash.InfoMsg | SanitizeHTML}}</p>
+ </div>
+{{end}}
+{{if .Flash.WarningMsg}}
+ <div class="ui warning message flash-message flash-warning">
+ <p>{{.Flash.WarningMsg | SanitizeHTML}}</p>
+ </div>
+{{end}}
diff --git a/templates/base/alert_details.tmpl b/templates/base/alert_details.tmpl
new file mode 100644
index 00000000..6801c824
--- /dev/null
+++ b/templates/base/alert_details.tmpl
@@ -0,0 +1,7 @@
+{{.Message}}
+<details>
+ <summary>{{.Summary}}</summary>
+ <code>
+ {{.Details | SanitizeHTML}}
+ </code>
+</details>
diff --git a/templates/base/disable_form_autofill.tmpl b/templates/base/disable_form_autofill.tmpl
new file mode 100644
index 00000000..6f06395b
--- /dev/null
+++ b/templates/base/disable_form_autofill.tmpl
@@ -0,0 +1,31 @@
+{{/*
+Why we need to disable form autofill:
+1. Many pages contain different password inputs for different usages, eg: repo setting, autofill will make a mess.
+2. We have `areYouSure` confirm dialog if a user leaves a pages without submit.
+Autofill will make the form changed even if the user didn't input anything. Then the user keeps seeing annoying confirm dialog.
+
+In history, Gitea put `<input class="fake" type="password">` in forms to bypass the autofill,
+but there were still many forms suffered the autofill problem.
+
+Now we improve it.
+
+Solutions which do NOT work:
+1. Adding `autocomplete=off` doesn't help. New Chrome completely ignores it.
+2. Use a JavaScript to run in a few seconds later after the page is loaded to process the autofilled inputs, it doesn't work.
+Because for security reason, the inputs won't be filled before the user makes an interaction in the page.
+So we can not predict the correct time to run the JavaScript code.
+
+Solutions which work:
+1. Some hacky methods like: https://github.com/matteobad/detect-autofill
+2. This solution: use invisible inputs. Be aware of:
+(a) The inputs must be at the beginning of the form, and can not be hidden.
+(b) The input for username must have a valid name.
+(c) There should be no negative word (eg: fake) in the `name` attribute.
+(d) Chrome seems to use a weighted algorithm to choose an input to fill text, so the using "username" as input name is better than using "user".
+We make the names of these dummy inputs begin with an underline to indicate it is for special usage,
+and these dummy form values won't be used by backend code.
+*/}}
+<div class="autofill-dummy" aria-hidden="true">
+ <input type="text" name="_autofill_dummy_username" class="ays-ignore" tabindex="-1">
+ <input type="password" name="_autofill_dummy_password" class="ays-ignore" tabindex="-1">
+</div>
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl
new file mode 100644
index 00000000..fed426a4
--- /dev/null
+++ b/templates/base/footer.tmpl
@@ -0,0 +1,20 @@
+{{if false}}
+ {{/* to make html structure "likely" complete to prevent IDE warnings */}}
+<html>
+<body>
+ <div>
+{{end}}
+
+ {{template "custom/body_inner_post" .}}
+
+ </div>
+
+ {{template "custom/body_outer_post" .}}
+
+ {{template "base/footer_content" .}}
+
+ <script src="{{AssetUrlPrefix}}/js/index.js?v={{AssetVersion}}" onerror="alert('Failed to load asset files from ' + this.src + '. Please make sure the asset files can be accessed.')"></script>
+
+ {{template "custom/footer" .}}
+</body>
+</html>
diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl
new file mode 100644
index 00000000..5db74644
--- /dev/null
+++ b/templates/base/footer_content.tmpl
@@ -0,0 +1,32 @@
+<footer class="page-footer" role="group" aria-label="{{ctx.Locale.Tr "aria.footer"}}">
+ <div class="left-links" role="contentinfo" aria-label="{{ctx.Locale.Tr "aria.footer.software"}}">
+ {{if ShowFooterPoweredBy}}
+ <a target="_blank" rel="noopener noreferrer" href="https://forgejo.org">{{ctx.Locale.Tr "powered_by" "Forgejo"}}</a>
+ {{end}}
+ {{if (or .ShowFooterVersion .PageIsAdmin)}}
+ {{ctx.Locale.Tr "version"}}:
+ {{if .IsAdmin}}
+ <a href="{{AppSubUrl}}/admin/config">{{AppVer}}</a>
+ {{else}}
+ {{AppVer}}
+ {{end}}
+ {{end}}
+ {{if and .TemplateLoadTimes ShowFooterTemplateLoadTime}}
+ {{ctx.Locale.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong>
+ {{ctx.Locale.Tr "template"}}{{if .TemplateName}} {{.TemplateName}}{{end}}: <strong>{{call .TemplateLoadTimes}}</strong>
+ {{end}}
+ </div>
+ <div class="right-links" role="group" aria-label="{{ctx.Locale.Tr "aria.footer.links"}}">
+ <div class="ui dropdown upward language">
+ <span class="flex-text-inline">{{svg "octicon-globe" 14}} {{ctx.Locale.LangName}}</span>
+ <div class="menu language-menu">
+ {{range .AllLangs}}
+ <a lang="{{.Lang}}" data-url="{{AppSubUrl}}/?lang={{.Lang}}" class="item {{if eq ctx.Locale.Lang .Lang}}active selected{{end}}">{{.Name}}</a>
+ {{end}}
+ </div>
+ </div>
+ <a href="{{AssetUrlPrefix}}/licenses.txt">{{ctx.Locale.Tr "licenses"}}</a>
+ {{if .EnableSwagger}}<a href="{{AppSubUrl}}/api/swagger">API</a>{{end}}
+ {{template "custom/extra_links_footer" .}}
+ </div>
+</footer>
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
new file mode 100644
index 00000000..7753f492
--- /dev/null
+++ b/templates/base/head.tmpl
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html lang="{{ctx.Locale.Lang}}" data-theme="{{ThemeName .SignedUser}}">
+<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ {{/* Display `- .Repository.FullName` only if `.Title` does not already start with that. */}}
+ <title>{{if .Title}}{{.Title}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppDisplayName}}</title>
+ {{if .ManifestData}}<link rel="manifest" href="data:{{.ManifestData}}">{{end}}
+ <meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}">
+ <meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}">
+ <meta name="keywords" content="{{MetaKeywords}}">
+ <meta name="referrer" content="no-referrer">
+{{if .GoGetImport}}
+ <meta name="go-import" content="{{.GoGetImport}} git {{.RepoCloneLink.HTTPS}}">
+ <meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}">
+{{end}}
+{{if and .EnableFeed .FeedURL}}
+ <link rel="alternate" type="application/atom+xml" title="" href="{{.FeedURL}}.atom">
+ <link rel="alternate" type="application/rss+xml" title="" href="{{.FeedURL}}.rss">
+{{end}}
+ <link rel="icon" href="{{AssetUrlPrefix}}/img/favicon.svg" type="image/svg+xml">
+ <link rel="alternate icon" href="{{AssetUrlPrefix}}/img/favicon.png" type="image/png">
+ {{template "base/head_script" .}}
+ <noscript>
+ <style>
+ .dropdown:hover > .menu { display: block; }
+ .ui.secondary.menu .dropdown.item > .menu { margin-top: 0; }
+ </style>
+ </noscript>
+ {{template "base/head_opengraph" .}}
+ {{template "base/head_style" .}}
+ {{template "custom/header" .}}
+</head>
+<body hx-headers='{"x-csrf-token": "{{.CsrfToken}}"}' hx-swap="outerHTML" hx-ext="morph" hx-push-url="false">
+ {{template "custom/body_outer_pre" .}}
+
+ <div class="full height">
+ <noscript>{{ctx.Locale.Tr "enable_javascript"}}</noscript>
+
+ {{template "custom/body_inner_pre" .}}
+
+ {{if not .PageIsInstall}}
+ {{template "base/head_navbar" .}}
+ {{end}}
+
+{{if false}}
+ {{/* to make html structure "likely" complete to prevent IDE warnings */}}
+ </div>
+</body>
+</html>
+{{end}}
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl
new file mode 100644
index 00000000..068271bb
--- /dev/null
+++ b/templates/base/head_navbar.tmpl
@@ -0,0 +1,205 @@
+{{$notificationUnreadCount := 0}}
+{{if and .IsSigned .NotificationUnreadCount}}
+ {{$notificationUnreadCount = call .NotificationUnreadCount}}
+{{end}}
+
+<nav id="navbar" aria-label="{{ctx.Locale.Tr "aria.navbar"}}">
+ <div class="navbar-left ui secondary menu">
+ <!-- the logo -->
+ <a class="item" id="navbar-logo" href="{{AppSubUrl}}/" aria-label="{{if .IsSigned}}{{ctx.Locale.Tr "dashboard"}}{{else}}{{ctx.Locale.Tr "home"}}{{end}}">
+ <img width="30" height="30" src="{{AssetUrlPrefix}}/img/logo.svg" alt="{{ctx.Locale.Tr "logo"}}" aria-hidden="true">
+ </a>
+
+ <!-- mobile right menu, it must be here because in mobile view, each item is a flex column, the first item is a full row column -->
+ <div class="ui secondary menu item navbar-mobile-right only-mobile">
+ {{if .IsSigned}}
+ <a id="mobile-notifications-icon" class="item tw-w-auto tw-p-2" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}" aria-label="{{ctx.Locale.Tr "notifications"}}">
+ <div class="tw-relative">
+ {{svg "octicon-bell"}}
+ <span class="notification_count{{if not $notificationUnreadCount}} tw-hidden{{end}}">{{$notificationUnreadCount}}</span>
+ </div>
+ </a>
+ {{end}}
+ <button class="item tw-w-auto ui icon mini button tw-p-2 tw-m-0" id="navbar-expand-toggle" aria-label="{{ctx.Locale.Tr "toggle_menu"}}">{{svg "octicon-three-bars"}}</button>
+ </div>
+
+ <!-- navbar links non-mobile -->
+ {{if and .IsSigned .MustChangePassword}}
+ {{/* No links */}}
+ {{else if .IsSigned}}
+ {{if not .UnitIssuesGlobalDisabled}}
+ <a class="item{{if .PageIsIssues}} active{{end}}" href="{{AppSubUrl}}/issues">{{ctx.Locale.Tr "issues"}}</a>
+ {{end}}
+ {{if not .UnitPullsGlobalDisabled}}
+ <a class="item{{if .PageIsPulls}} active{{end}}" href="{{AppSubUrl}}/pulls">{{ctx.Locale.Tr "pull_requests"}}</a>
+ {{end}}
+ {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}}
+ {{if .ShowMilestonesDashboardPage}}
+ <a class="item{{if .PageIsMilestonesDashboard}} active{{end}}" href="{{AppSubUrl}}/milestones">{{ctx.Locale.Tr "milestones"}}</a>
+ {{end}}
+ {{end}}
+ <a class="item{{if .PageIsExplore}} active{{end}}" href="{{AppSubUrl}}/explore/repos">{{ctx.Locale.Tr "explore"}}</a>
+ {{else if .IsLandingPageOrganizations}}
+ <a class="item{{if .PageIsExplore}} active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{ctx.Locale.Tr "explore"}}</a>
+ {{else}}
+ <a class="item{{if .PageIsExplore}} active{{end}}" href="{{AppSubUrl}}/explore/repos">{{ctx.Locale.Tr "explore"}}</a>
+ {{end}}
+
+ {{template "custom/extra_links" .}}
+
+ {{if not .IsSigned}}
+ <a class="item" target="_blank" rel="noopener noreferrer" href="https://forgejo.org/docs/latest/">{{ctx.Locale.Tr "help"}}</a>
+ {{end}}
+ </div>
+
+ <!-- the full dropdown menus -->
+ <div class="navbar-right ui secondary menu">
+ {{if and .IsSigned .MustChangePassword}}
+ <div class="ui dropdown jump item" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
+ <span class="text tw-flex tw-items-center">
+ {{ctx.AvatarUtils.Avatar .SignedUser 24 "tw-mr-1"}}
+ <span class="only-mobile tw-ml-2">{{.SignedUser.Name}}</span>
+ <span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
+ </span>
+ <div class="menu user-menu">
+ <div class="ui header">
+ {{ctx.Locale.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong>
+ </div>
+
+ <div class="divider"></div>
+ <a class="item link-action" href data-url="{{AppSubUrl}}/user/logout">
+ {{svg "octicon-sign-out"}}
+ {{ctx.Locale.Tr "sign_out"}}
+ </a>
+ </div><!-- end content avatar menu -->
+ </div><!-- end dropdown avatar menu -->
+ {{else if .IsSigned}}
+ {{if EnableTimetracking}}
+ <a class="active-stopwatch-trigger item tw-mx-0{{if not .ActiveStopwatch}} tw-hidden{{end}}" href="{{.ActiveStopwatch.IssueLink}}" title="{{ctx.Locale.Tr "active_stopwatch"}}">
+ <div class="tw-relative">
+ {{svg "octicon-stopwatch"}}
+ <span class="header-stopwatch-dot"></span>
+ </div>
+ <span class="only-mobile tw-ml-2">{{ctx.Locale.Tr "active_stopwatch"}}</span>
+ </a>
+ <div class="active-stopwatch-popup item tippy-target tw-p-2">
+ <div class="tw-flex tw-items-center">
+ <a class="stopwatch-link tw-flex tw-items-center" href="{{.ActiveStopwatch.IssueLink}}">
+ {{svg "octicon-issue-opened" 16 "tw-mr-2"}}
+ <span class="stopwatch-issue">{{.ActiveStopwatch.RepoSlug}}#{{.ActiveStopwatch.IssueIndex}}</span>
+ <span class="ui primary label stopwatch-time tw-my-0 tw-mx-4" data-seconds="{{.ActiveStopwatch.Seconds}}">
+ {{if .ActiveStopwatch}}{{Sec2Time .ActiveStopwatch.Seconds}}{{end}}
+ </span>
+ </a>
+ <form class="stopwatch-commit" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/toggle">
+ {{.CsrfTokenHtml}}
+ <button
+ type="submit"
+ class="ui button mini compact basic icon"
+ data-tooltip-content="{{ctx.Locale.Tr "repo.issues.stop_tracking"}}"
+ >{{svg "octicon-square-fill"}}</button>
+ </form>
+ <form class="stopwatch-cancel" method="post" action="{{.ActiveStopwatch.IssueLink}}/times/stopwatch/cancel">
+ {{.CsrfTokenHtml}}
+ <button
+ type="submit"
+ class="ui button mini compact basic icon"
+ data-tooltip-content="{{ctx.Locale.Tr "repo.issues.cancel_tracking"}}"
+ >{{svg "octicon-trash"}}</button>
+ </form>
+ </div>
+ </div>
+ {{end}}
+
+ <a class="item not-mobile tw-mx-0" href="{{AppSubUrl}}/notifications" data-tooltip-content="{{ctx.Locale.Tr "notifications"}}" aria-label="{{ctx.Locale.Tr "notifications"}}">
+ <div class="tw-relative">
+ {{svg "octicon-bell"}}
+ <span class="notification_count{{if not $notificationUnreadCount}} tw-hidden{{end}}">{{$notificationUnreadCount}}</span>
+ </div>
+ </a>
+
+ <div class="ui dropdown jump item tw-mx-0 tw-pr-2" data-tooltip-content="{{ctx.Locale.Tr "create_new"}}">
+ <span class="text">
+ {{svg "octicon-plus"}}
+ <span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
+ <span class="only-mobile">{{ctx.Locale.Tr "create_new"}}</span>
+ </span>
+ <div class="menu">
+ <a class="item" href="{{AppSubUrl}}/repo/create">
+ {{svg "octicon-plus"}} {{ctx.Locale.Tr "new_repo"}}
+ </a>
+ {{if not .DisableMigrations}}
+ <a class="item" href="{{AppSubUrl}}/repo/migrate">
+ {{svg "octicon-repo-push"}} {{ctx.Locale.Tr "new_migrate"}}
+ </a>
+ {{end}}
+ {{if .SignedUser.CanCreateOrganization}}
+ <a class="item" href="{{AppSubUrl}}/org/create">
+ {{svg "octicon-organization"}} {{ctx.Locale.Tr "new_org"}}
+ </a>
+ {{end}}
+ </div><!-- end content create new menu -->
+ </div><!-- end dropdown menu create new -->
+
+ <div class="ui dropdown jump item tw-mx-0 tw-pr-2" data-tooltip-content="{{ctx.Locale.Tr "user_profile_and_more"}}">
+ <span class="text tw-flex tw-items-center">
+ {{ctx.AvatarUtils.Avatar .SignedUser 24 "tw-mr-1"}}
+ <span class="only-mobile tw-ml-2">{{.SignedUser.Name}}</span>
+ <span class="not-mobile">{{svg "octicon-triangle-down"}}</span>
+ </span>
+ <div class="menu user-menu">
+ <div class="ui header">
+ {{ctx.Locale.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong>
+ </div>
+
+ <div class="divider"></div>
+ <a class="item" href="{{.SignedUser.HomeLink}}">
+ {{svg "octicon-person"}}
+ {{ctx.Locale.Tr "your_profile"}}
+ </a>
+ {{if not .DisableStars}}
+ <a class="item" href="{{.SignedUser.HomeLink}}?tab=stars">
+ {{svg "octicon-star"}}
+ {{ctx.Locale.Tr "your_starred"}}
+ </a>
+ {{end}}
+ <a class="item" href="{{AppSubUrl}}/notifications/subscriptions">
+ {{svg "octicon-bell"}}
+ {{ctx.Locale.Tr "notification.subscriptions"}}
+ </a>
+ <a class="{{if .PageIsUserSettings}}active {{end}}item" href="{{AppSubUrl}}/user/settings">
+ {{svg "octicon-tools"}}
+ {{ctx.Locale.Tr "your_settings"}}
+ </a>
+ <a class="item" target="_blank" rel="noopener noreferrer" href="https://forgejo.org/docs/latest/">
+ {{svg "octicon-question"}}
+ {{ctx.Locale.Tr "help"}}
+ </a>
+ {{if .IsAdmin}}
+ <div class="divider"></div>
+
+ <a class="{{if .PageIsAdmin}}active {{end}}item" href="{{AppSubUrl}}/admin">
+ {{svg "octicon-server"}}
+ {{ctx.Locale.Tr "admin_panel"}}
+ </a>
+ {{end}}
+
+ <div class="divider"></div>
+ <a class="item link-action" href data-url="{{AppSubUrl}}/user/logout">
+ {{svg "octicon-sign-out"}}
+ {{ctx.Locale.Tr "sign_out"}}
+ </a>
+ </div><!-- end content avatar menu -->
+ </div><!-- end dropdown avatar menu -->
+ {{else}}
+ {{if .ShowRegistrationButton}}
+ <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up">
+ {{svg "octicon-person"}} {{ctx.Locale.Tr "register"}}
+ </a>
+ {{end}}
+ <a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login{{if not .PageIsSignIn}}?redirect_to={{.CurrentURL}}{{end}}">
+ {{svg "octicon-sign-in"}} {{ctx.Locale.Tr "sign_in"}}
+ </a>
+ {{end}}
+ </div><!-- end full right menu -->
+</nav>
diff --git a/templates/base/head_opengraph.tmpl b/templates/base/head_opengraph.tmpl
new file mode 100644
index 00000000..c02adaba
--- /dev/null
+++ b/templates/base/head_opengraph.tmpl
@@ -0,0 +1,47 @@
+{{- /* og:description - a one to two sentence description of your object, maybe it only needs at most 300 bytes */ -}}
+{{if .PageIsUserProfile}}
+ <meta property="og:title" content="{{.ContextUser.DisplayName}}">
+ <meta property="og:type" content="profile">
+ <meta property="og:image" content="{{.ContextUser.AvatarLink ctx}}">
+ <meta property="og:url" content="{{.ContextUser.HTMLURL}}">
+ {{if .ContextUser.Description}}
+ <meta property="og:description" content="{{StringUtils.EllipsisString .ContextUser.Description 300}}">
+ {{end}}
+{{else if .Repository}}
+ {{if .Issue}}
+ <meta property="og:title" content="{{.Issue.Title}}">
+ <meta property="og:url" content="{{.Issue.HTMLURL}}">
+ {{if .Issue.Content}}
+ <meta property="og:description" content="{{StringUtils.EllipsisString .Issue.Content 300}}">
+ {{end}}
+ {{else if or .PageIsDiff .IsViewFile}}
+ <meta property="og:title" content="{{.Title}}">
+ <meta property="og:url" content="{{AppUrl}}{{.Link}}">
+ {{if and .PageIsDiff .Commit}}
+ {{- $commitMessageParts := StringUtils.Cut .Commit.Message "\n" -}}
+ {{- $commitMessageBody := index $commitMessageParts 1 -}}
+ {{- if $commitMessageBody -}}
+ <meta property="og:description" content="{{StringUtils.EllipsisString $commitMessageBody 300}}">
+ {{- end -}}
+ {{end}}
+ {{else}}
+ <meta property="og:title" content="{{.Repository.Name}}">
+ <meta property="og:url" content="{{.Repository.HTMLURL}}">
+ {{if .Repository.Description}}
+ <meta property="og:description" content="{{StringUtils.EllipsisString .Repository.Description 300}}">
+ {{end}}
+ {{end}}
+ <meta property="og:type" content="object">
+ {{if (.Repository.AvatarLink ctx)}}
+ <meta property="og:image" content="{{.Repository.AvatarLink ctx}}">
+ {{else}}
+ <meta property="og:image" content="{{.Repository.Owner.AvatarLink ctx}}">
+ {{end}}
+{{else}}
+ <meta property="og:title" content="{{AppDisplayName}}">
+ <meta property="og:type" content="website">
+ <meta property="og:image" content="{{AssetUrlPrefix}}/img/logo.png">
+ <meta property="og:url" content="{{AppUrl}}">
+ <meta property="og:description" content="{{MetaDescription}}">
+{{end}}
+<meta property="og:site_name" content="{{AppDisplayName}}">
diff --git a/templates/base/head_script.tmpl b/templates/base/head_script.tmpl
new file mode 100644
index 00000000..22e08e9c
--- /dev/null
+++ b/templates/base/head_script.tmpl
@@ -0,0 +1,50 @@
+{{/*
+==== DO NOT EDIT ====
+If you are customizing Gitea, please do not change this file.
+If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
+*/}}
+<script>
+ {{/* before our JS code gets loaded, use arrays to store errors, then the arrays will be switched to our error handler later */}}
+ window.addEventListener('error', function(e) {window._globalHandlerErrors=window._globalHandlerErrors||[]; window._globalHandlerErrors.push(e);});
+ window.addEventListener('unhandledrejection', function(e) {window._globalHandlerErrors=window._globalHandlerErrors||[]; window._globalHandlerErrors.push(e);});
+ window.config = {
+ appUrl: '{{AppUrl}}',
+ appSubUrl: '{{AppSubUrl}}',
+ assetVersionEncoded: encodeURIComponent('{{AssetVersion}}'), // will be used in URL construction directly
+ assetUrlPrefix: '{{AssetUrlPrefix}}',
+ runModeIsProd: {{.RunModeIsProd}},
+ customEmojis: {{CustomEmojis}},
+ csrfToken: '{{.CsrfToken}}',
+ pageData: {{.PageData}},
+ notificationSettings: {{NotificationSettings}}, {{/*a map provided by NewFuncMap in helper.go*/}}
+ enableTimeTracking: {{EnableTimetracking}},
+ {{if or .Participants .Assignees .MentionableTeams}}
+ mentionValues: Array.from(new Map([
+ {{- range .Participants -}}
+ ['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink $.Context}}'}],
+ {{- end -}}
+ {{- range .Assignees -}}
+ ['{{.Name}}', {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.AvatarLink $.Context}}'}],
+ {{- end -}}
+ {{- range .MentionableTeams -}}
+ ['{{$.MentionableTeamsOrg}}/{{.Name}}', {key: '{{$.MentionableTeamsOrg}}/{{.Name}}', value: '{{$.MentionableTeamsOrg}}/{{.Name}}', name: '{{$.MentionableTeamsOrg}}/{{.Name}}', avatar: '{{$.MentionableTeamsOrgAvatar}}'}],
+ {{- end -}}
+ ]).values()),
+ {{end}}
+ mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}},
+ {{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}}
+ i18n: {
+ copy_success: {{ctx.Locale.Tr "copy_success"}},
+ copy_error: {{ctx.Locale.Tr "copy_error"}},
+ error_occurred: {{ctx.Locale.Tr "error.occurred"}},
+ network_error: {{ctx.Locale.Tr "error.network_error"}},
+ remove_label_str: {{ctx.Locale.Tr "remove_label_str"}},
+ modal_confirm: {{ctx.Locale.Tr "modal.confirm"}},
+ modal_cancel: {{ctx.Locale.Tr "modal.cancel"}},
+ more_items: {{ctx.Locale.Tr "more_items"}},
+ },
+ };
+ {{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}}
+ window.config.pageData = window.config.pageData || {};
+</script>
+<script src="{{AssetUrlPrefix}}/js/webcomponents.js?v={{AssetVersion}}"></script>
diff --git a/templates/base/head_style.tmpl b/templates/base/head_style.tmpl
new file mode 100644
index 00000000..0793eaca
--- /dev/null
+++ b/templates/base/head_style.tmpl
@@ -0,0 +1,2 @@
+<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/index.css?v={{AssetVersion}}">
+<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{ThemeName .SignedUser | PathEscape}}.css?v={{AssetVersion}}">
diff --git a/templates/base/modal_actions_confirm.tmpl b/templates/base/modal_actions_confirm.tmpl
new file mode 100644
index 00000000..c44320de
--- /dev/null
+++ b/templates/base/modal_actions_confirm.tmpl
@@ -0,0 +1,35 @@
+{{/*
+Two buttons (negative, positive):
+* ModalButtonTypes: "yes" (default) or "confirm"
+* ModalButtonColors: "primary" (default) / "blue" / "yellow"
+* ModalButtonCancelText
+* ModalButtonOkText
+
+Single danger button (GitHub-like):
+* ModalButtonDangerText "This action will destroy your data"
+
+The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal internally
+*/}}
+<div class="actions">
+ {{if .ModalButtonDangerText}}
+ <button class="ui danger red ok button">{{.ModalButtonDangerText}}</button>
+ {{else}}
+ {{$textNegitive := ctx.Locale.Tr "modal.no"}}
+ {{$textPositive := ctx.Locale.Tr "modal.yes"}}
+ {{if eq .ModalButtonTypes "confirm"}}
+ {{$textNegitive = ctx.Locale.Tr "modal.cancel"}}
+ {{$textPositive = ctx.Locale.Tr "modal.confirm"}}
+ {{end}}
+ {{if .ModalButtonCancelText}}{{$textNegitive = .ModalButtonCancelText}}{{end}}
+ {{if .ModalButtonOkText}}{{$textPositive = .ModalButtonOkText}}{{end}}
+
+ {{$stylePositive := "primary"}}
+ {{if eq .ModalButtonColors "blue"}}
+ {{$stylePositive = "blue"}}
+ {{else if eq .ModalButtonColors "yellow"}}
+ {{$stylePositive = "yellow"}}
+ {{end}}
+ <button class="ui cancel button">{{svg "octicon-x"}} {{$textNegitive}}</button>
+ <button class="ui {{$stylePositive}} ok button">{{svg "octicon-check"}} {{$textPositive}}</button>
+ {{end}}
+</div>
diff --git a/templates/base/paginate.tmpl b/templates/base/paginate.tmpl
new file mode 100644
index 00000000..2ca72f6a
--- /dev/null
+++ b/templates/base/paginate.tmpl
@@ -0,0 +1,34 @@
+{{$paginationParams := .Page.GetParams}}
+{{$paginationLink := $.Link}}
+{{if eq $paginationLink AppSubUrl}}{{$paginationLink = print $paginationLink "/"}}{{end}}
+{{with .Page.Paginater}}
+ {{if gt .TotalPages 1}}
+ <div class="center page buttons">
+ <div class="ui borderless pagination menu">
+ <a class="{{if .IsFirst}}disabled{{end}} item navigation" {{if not .IsFirst}}href="{{$paginationLink}}{{if $paginationParams}}?{{$paginationParams}}{{end}}"{{end}}>
+ {{svg "gitea-double-chevron-left" 16 "tw-mr-1"}}
+ <span class="navigation_label">{{ctx.Locale.Tr "admin.first_page"}}</span>
+ </a>
+ <a class="{{if not .HasPrevious}}disabled{{end}} item navigation" {{if .HasPrevious}}href="{{$paginationLink}}?page={{.Previous}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>
+ {{svg "octicon-chevron-left" 16 "tw-mr-1"}}
+ <span class="navigation_label">{{ctx.Locale.Tr "repo.issues.previous"}}</span>
+ </a>
+ {{range .Pages}}
+ {{if eq .Num -1}}
+ <a class="disabled item">...</a>
+ {{else}}
+ <a class="{{if .IsCurrent}}active {{end}}item tw-items-center" {{if not .IsCurrent}}href="{{$paginationLink}}?page={{.Num}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>{{.Num}}</a>
+ {{end}}
+ {{end}}
+ <a class="{{if not .HasNext}}disabled{{end}} item navigation" {{if .HasNext}}href="{{$paginationLink}}?page={{.Next}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>
+ <span class="navigation_label">{{ctx.Locale.Tr "repo.issues.next"}}</span>
+ {{svg "octicon-chevron-right" 16 "tw-ml-1"}}
+ </a>
+ <a class="{{if .IsLast}}disabled{{end}} item navigation" {{if not .IsLast}}href="{{$paginationLink}}?page={{.TotalPages}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>
+ <span class="navigation_label">{{ctx.Locale.Tr "admin.last_page"}}</span>
+ {{svg "gitea-double-chevron-right" 16 "tw-ml-1"}}
+ </a>
+ </div>
+ </div>
+ {{end}}
+{{end}}