diff --git a/.github/labeler.yml b/.github/labeler.yml index 8a5ab26975ea0..a1209c77b8c51 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,36 +1,84 @@ modifies/docs: - - "**/*.md" - - "docs/**" + - changed-files: + - any-glob-to-any-file: + - "**/*.md" + - "docs/**" modifies/frontend: - - "web_src/**/*" + - changed-files: + - any-glob-to-any-file: + - "web_src/**" + - "tailwind.config.js" + - "webpack.config.js" modifies/templates: - - all: ["templates/**", "!templates/swagger/v1_json.tmpl"] + - changed-files: + - all-globs-to-any-file: + - "templates/**" + - "!templates/swagger/v1_json.tmpl" modifies/api: - - "routers/api/**" - - "templates/swagger/v1_json.tmpl" + - changed-files: + - any-glob-to-any-file: + - "routers/api/**" + - "templates/swagger/v1_json.tmpl" modifies/cli: - - "cmd/**" + - changed-files: + - any-glob-to-any-file: + - "cmd/**" modifies/translation: - - "options/locale/*.ini" + - changed-files: + - any-glob-to-any-file: + - "options/locale/*.ini" modifies/migrations: - - "models/migrations/**/*" + - changed-files: + - any-glob-to-any-file: + - "models/migrations/**" modifies/internal: - - "Makefile" - - "Dockerfile" - - "Dockerfile.rootless" - - "docker/**" - - "webpack.config.js" - - ".eslintrc.yaml" - - ".golangci.yml" - - ".markdownlint.yaml" - - ".spectral.yaml" - - ".stylelintrc.yaml" - - ".yamllint.yaml" - - ".github/**" + - changed-files: + - any-glob-to-any-file: + - ".air.toml" + - "Makefile" + - "Dockerfile" + - "Dockerfile.rootless" + - ".dockerignore" + - "docker/**" + - ".editorconfig" + - ".eslintrc.yaml" + - ".golangci.yml" + - ".gitpod.yml" + - ".markdownlint.yaml" + - ".spectral.yaml" + - ".stylelintrc.yaml" + - ".yamllint.yaml" + - ".github/**" + - ".gitea/" + - ".devcontainer/**" + - "build.go" + - "build/**" + - "contrib/**" + +modifies/dependencies: + - changed-files: + - any-glob-to-any-file: + - "package.json" + - "package-lock.json" + - "poetry.toml" + - "poetry.lock" + - "go.mod" + - "go.sum" + - "pyproject.toml" + +modifies/go: + - changed-files: + - any-glob-to-any-file: + - "**/*.go" + +modifies/js: + - changed-files: + - any-glob-to-any-file: + - "**/*.js" diff --git a/.github/workflows/pull-labeler.yml b/.github/workflows/pull-labeler.yml index edd2f6d16e637..812819b5991ed 100644 --- a/.github/workflows/pull-labeler.yml +++ b/.github/workflows/pull-labeler.yml @@ -9,12 +9,12 @@ concurrency: cancel-in-progress: true jobs: - label: + labeler: runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - - uses: actions/labeler@v4 + - uses: actions/labeler@v5 with: - dot: true + sync-labels: true diff --git a/go.mod b/go.mod index 9b70a191ce57e..97f429aadb9c3 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 github.com/NYTimes/gziphandler v1.1.1 github.com/PuerkitoBio/goquery v1.8.1 - github.com/alecthomas/chroma/v2 v2.12.0 + github.com/alecthomas/chroma/v2 v2.13.0 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.3.10 github.com/bufbuild/connect-go v1.10.0 @@ -172,7 +172,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidmz/go-pageant v1.0.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dlclark/regexp2 v1.10.0 // indirect + github.com/dlclark/regexp2 v1.11.0 // indirect github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect diff --git a/go.sum b/go.sum index a44809dde5810..916378d759969 100644 --- a/go.sum +++ b/go.sum @@ -104,14 +104,14 @@ github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06 github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= github.com/RoaringBitmap/roaring v1.7.0 h1:OZF303tJCER1Tj3x+aArx/S5X7hrT186ri6JjrGvG68= github.com/RoaringBitmap/roaring v1.7.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= -github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink= -github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= +github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= +github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw= -github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw= +github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI= +github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= -github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= -github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= @@ -260,8 +260,8 @@ github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmW github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= -github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index cdff31698ca13..ba9b050e02aa9 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/util" ) @@ -118,10 +119,15 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string) } // RenderLabel renders a label -func RenderLabel(ctx context.Context, label *issues_model.Label) template.HTML { - labelScope := label.ExclusiveScope() +// locale is needed due to an import cycle with our context providing the `Tr` function +func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML { + var ( + archivedCSSClass string + textColor = "#111" + isArchived = !label.ArchivedUnix.IsZero() + labelScope = label.ExclusiveScope() + ) - textColor := "#111" r, g, b := util.HexToRBGColor(label.Color) // Determine if label text should be light or dark to be readable on background color if util.UseLightTextOnBackground(r, g, b) { @@ -130,10 +136,15 @@ func RenderLabel(ctx context.Context, label *issues_model.Label) template.HTML { description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description)) + if isArchived { + archivedCSSClass = "archived-label" + description = fmt.Sprintf("(%s) %s", locale.TrString("archived"), description) + } + if labelScope == "" { // Regular label - s := fmt.Sprintf("
%s
", - textColor, label.Color, description, RenderEmoji(ctx, label.Name)) + s := fmt.Sprintf("
%s
", + archivedCSSClass, textColor, label.Color, description, RenderEmoji(ctx, label.Name)) return template.HTML(s) } @@ -166,11 +177,11 @@ func RenderLabel(ctx context.Context, label *issues_model.Label) template.HTML { itemColor := "#" + hex.EncodeToString(itemBytes) scopeColor := "#" + hex.EncodeToString(scopeBytes) - s := fmt.Sprintf(""+ + s := fmt.Sprintf(""+ "
%s
"+ "
%s
"+ "
", - description, + archivedCSSClass, description, textColor, scopeColor, scopeText, textColor, itemColor, itemText) return template.HTML(s) @@ -211,7 +222,7 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n return output } -func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML { +func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string) template.HTML { htmlCode := `` for _, label := range labels { // Protect against nil value in labels - shouldn't happen but would cause a panic if so @@ -219,7 +230,7 @@ func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink st continue } htmlCode += fmt.Sprintf("%s ", - repoLink, label.ID, RenderLabel(ctx, label)) + repoLink, label.ID, RenderLabel(ctx, locale, label)) } htmlCode += "" return template.HTML(htmlCode) diff --git a/modules/timeutil/datetime.go b/modules/timeutil/datetime.go index 62b94f7cf481c..50c8d44f132be 100644 --- a/modules/timeutil/datetime.go +++ b/modules/timeutil/datetime.go @@ -51,18 +51,16 @@ func DateTime(format string, datetime any, extraAttrs ...string) template.HTML { attrs := make([]string, 0, 10+len(extraAttrs)) attrs = append(attrs, extraAttrs...) - attrs = append(attrs, `data-tooltip-content`, `data-tooltip-interactive="true"`) - attrs = append(attrs, `format="datetime"`, `weekday=""`, `year="numeric"`) + attrs = append(attrs, `weekday=""`, `year="numeric"`) switch format { - case "short": - attrs = append(attrs, `month="short"`, `day="numeric"`) - case "long": - attrs = append(attrs, `month="long"`, `day="numeric"`) - case "full": - attrs = append(attrs, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`) + case "short", "long": // date only + attrs = append(attrs, `month="`+format+`"`, `day="numeric"`) + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) + case "full": // full date including time + attrs = append(attrs, `format="datetime"`, `month="short"`, `day="numeric"`, `hour="numeric"`, `minute="numeric"`, `second="numeric"`, `data-tooltip-content`, `data-tooltip-interactive="true"`) + return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) default: panic(fmt.Sprintf("Unsupported format %s", format)) } - return template.HTML(fmt.Sprintf(`%s`, strings.Join(attrs, " "), datetimeEscaped, textEscaped)) } diff --git a/modules/timeutil/datetime_test.go b/modules/timeutil/datetime_test.go index 26494b84754f9..39aecbc43bdf6 100644 --- a/modules/timeutil/datetime_test.go +++ b/modules/timeutil/datetime_test.go @@ -18,6 +18,7 @@ func TestDateTime(t *testing.T) { defer test.MockVariableValue(&setting.DefaultUILocation, testTz)() refTimeStr := "2018-01-01T00:00:00Z" + refDateStr := "2018-01-01" refTime, _ := time.Parse(time.RFC3339, refTimeStr) refTimeStamp := TimeStamp(refTime.Unix()) @@ -27,17 +28,20 @@ func TestDateTime(t *testing.T) { assert.EqualValues(t, "-", DateTime("short", TimeStamp(0))) actual := DateTime("short", "invalid") - assert.EqualValues(t, `invalid`, actual) + assert.EqualValues(t, `invalid`, actual) actual = DateTime("short", refTimeStr) - assert.EqualValues(t, `2018-01-01T00:00:00Z`, actual) + assert.EqualValues(t, `2018-01-01T00:00:00Z`, actual) actual = DateTime("short", refTime) - assert.EqualValues(t, `2018-01-01`, actual) + assert.EqualValues(t, `2018-01-01`, actual) + + actual = DateTime("short", refDateStr) + assert.EqualValues(t, `2018-01-01`, actual) actual = DateTime("short", refTimeStamp) - assert.EqualValues(t, `2017-12-31`, actual) + assert.EqualValues(t, `2017-12-31`, actual) actual = DateTime("full", refTimeStamp) - assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) + assert.EqualValues(t, `2017-12-31 19:00:00 -05:00`, actual) } diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index ccf188609c91d..e551572b96c1b 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -110,6 +110,16 @@
+
+

GiteaAbsoluteDate

+
+
+
+
+
+
relative-time:
+
+

LocaleNumber

{{ctx.Locale.PrettyNumber 1}}
diff --git a/templates/repo/issue/filter_actions.tmpl b/templates/repo/issue/filter_actions.tmpl index a2296f6597bd3..f573b8e09ea2d 100644 --- a/templates/repo/issue/filter_actions.tmpl +++ b/templates/repo/issue/filter_actions.tmpl @@ -30,7 +30,7 @@ {{end}} {{$previousExclusiveScope = $exclusiveScope}}
- {{if SliceUtils.Contains $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context .}} + {{if SliceUtils.Contains $.SelLabelIDs .ID}}{{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}{{end}} {{RenderLabel $.Context ctx.Locale .}} {{template "repo/issue/labels/label_archived" .}}
{{end}} diff --git a/templates/repo/issue/filter_list.tmpl b/templates/repo/issue/filter_list.tmpl index 9d3341cc814cd..d0086fdf8c2b6 100644 --- a/templates/repo/issue/filter_list.tmpl +++ b/templates/repo/issue/filter_list.tmpl @@ -42,7 +42,7 @@ {{svg "octicon-check"}} {{end}} {{end}} - {{RenderLabel $.Context .}} + {{RenderLabel $.Context ctx.Locale .}}

{{template "repo/issue/labels/label_archived" .}}

{{end}} diff --git a/templates/repo/issue/labels/label.tmpl b/templates/repo/issue/labels/label.tmpl index 3ecae09373888..d20d5e63d7498 100644 --- a/templates/repo/issue/labels/label.tmpl +++ b/templates/repo/issue/labels/label.tmpl @@ -3,5 +3,5 @@ id="label_{{.label.ID}}" href="{{.root.RepoLink}}/{{if or .root.IsPull .root.Issue.IsPull}}pulls{{else}}issues{{end}}?labels={{.label.ID}}"{{/* FIXME: use .root.Issue.Link or create .root.Link */}} > - {{- RenderLabel $.Context .label -}} + {{- RenderLabel $.Context ctx.Locale .label -}} diff --git a/templates/repo/issue/labels/label_list.tmpl b/templates/repo/issue/labels/label_list.tmpl index 9b0061b60ebd6..428a4919aa1fe 100644 --- a/templates/repo/issue/labels/label_list.tmpl +++ b/templates/repo/issue/labels/label_list.tmpl @@ -32,7 +32,7 @@ {{range .Labels}}
  • - {{RenderLabel $.Context .}} + {{RenderLabel $.Context ctx.Locale .}} {{if .Description}}
    {{.Description | RenderEmoji $.Context}}{{end}}
    @@ -72,7 +72,7 @@ {{range .OrgLabels}}
  • - {{RenderLabel $.Context .}} + {{RenderLabel $.Context ctx.Locale .}} {{if .Description}}
    {{.Description | RenderEmoji $.Context}}{{end}}
    diff --git a/templates/repo/issue/labels/labels_selector_field.tmpl b/templates/repo/issue/labels/labels_selector_field.tmpl index e42a1de8952dc..a9c33bc4eb715 100644 --- a/templates/repo/issue/labels/labels_selector_field.tmpl +++ b/templates/repo/issue/labels/labels_selector_field.tmpl @@ -21,7 +21,7 @@
    {{end}} {{$previousExclusiveScope = $exclusiveScope}} - {{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}  {{RenderLabel $.Context .}} + {{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}  {{RenderLabel $.Context ctx.Locale .}} {{if .Description}}
    {{.Description | RenderEmoji $.Context}}{{end}}

    {{template "repo/issue/labels/label_archived" .}}

    @@ -34,7 +34,7 @@
    {{end}} {{$previousExclusiveScope = $exclusiveScope}} - {{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}  {{RenderLabel $.Context .}} + {{if $exclusiveScope}}{{svg "octicon-dot-fill"}}{{else}}{{svg "octicon-check"}}{{end}}  {{RenderLabel $.Context ctx.Locale .}} {{if .Description}}
    {{.Description | RenderEmoji $.Context}}{{end}}

    {{template "repo/issue/labels/label_archived" .}}

    diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 8bbcb1a54a941..db63e2b951984 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -173,11 +173,11 @@ {{template "shared/user/authorlink" .Poster}} {{if and .AddedLabels (not .RemovedLabels)}} - {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) $createdStr}} + {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink) $createdStr}} {{else if and (not .AddedLabels) .RemovedLabels}} - {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr}} + {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink) $createdStr}} {{else}} - {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context .AddedLabels $.RepoLink) (RenderLabels $.Context .RemovedLabels $.RepoLink) $createdStr}} + {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink) (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink) $createdStr}} {{end}}
    diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index a90188297f66d..cffe579741e6d 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -21,7 +21,7 @@ {{end}} {{range .Labels}} - {{RenderLabel $.Context .}} + {{RenderLabel $.Context ctx.Locale .}} {{end}}
  • diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 03d9664331fda..587a3152e5562 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2417,6 +2417,10 @@ gap: 0 !important; } +.archived-label { + filter: grayscale(0.8); +} + .ui.label.scope-left { border-bottom-right-radius: 0; border-top-right-radius: 0; diff --git a/web_src/js/webcomponents/GiteaAbsoluteDate.js b/web_src/js/webcomponents/GiteaAbsoluteDate.js new file mode 100644 index 0000000000000..660aa99d07036 --- /dev/null +++ b/web_src/js/webcomponents/GiteaAbsoluteDate.js @@ -0,0 +1,40 @@ +window.customElements.define('gitea-absolute-date', class extends HTMLElement { + static observedAttributes = ['date', 'year', 'month', 'weekday', 'day']; + + update = () => { + const year = this.getAttribute('year') ?? ''; + const month = this.getAttribute('month') ?? ''; + const weekday = this.getAttribute('weekday') ?? ''; + const day = this.getAttribute('day') ?? ''; + const lang = this.closest('[lang]')?.getAttribute('lang') || + this.ownerDocument.documentElement.getAttribute('lang') || + ''; + + // only extract the `yyyy-mm-dd` part. When converting to Date, it will become midnight UTC and when rendered + // as localized date, will have a offset towards UTC, which we remove to shift the timestamp to midnight in the + // localized date. We should eventually use `Temporal.PlainDate` which will make the correction unnecessary. + // - https://stackoverflow.com/a/14569783/808699 + // - https://tc39.es/proposal-temporal/docs/plaindate.html + const date = new Date(this.getAttribute('date').substring(0, 10)); + const correctedDate = new Date(date.getTime() - date.getTimezoneOffset() * -60000); + + if (!this.shadowRoot) this.attachShadow({mode: 'open'}); + this.shadowRoot.textContent = correctedDate.toLocaleString(lang ?? [], { + ...(year && {year}), + ...(month && {month}), + ...(weekday && {weekday}), + ...(day && {day}), + }); + }; + + attributeChangedCallback(_name, oldValue, newValue) { + if (!this.initialized || oldValue === newValue) return; + this.update(); + } + + connectedCallback() { + this.initialized = false; + this.update(); + this.initialized = true; + } +}); diff --git a/web_src/js/webcomponents/webcomponents.js b/web_src/js/webcomponents/webcomponents.js index 916a588db64bf..03348d895fe4a 100644 --- a/web_src/js/webcomponents/webcomponents.js +++ b/web_src/js/webcomponents/webcomponents.js @@ -3,3 +3,4 @@ import './polyfill.js'; import '@github/relative-time-element'; import './GiteaOriginUrl.js'; +import './GiteaAbsoluteDate.js';