From 62d4b3da4de1732a8c525f845759b6962a95bacb Mon Sep 17 00:00:00 2001 From: whereareiam Date: Thu, 22 Oct 2026 20:41:13 +0200 Subject: [PATCH] feat(settings): GitHub's settings layout for repository, personal, org and admin One shared component (components/common/settings) styles every settings area, which their layouts mark with .theme-settings: a 256px nav 40px from the page with an icon per page, group labels (Access, Code and automation, Security, Integrations), GitHub's blue bar beside the current page and collapsible groups with the chevron on the right; sections as GitHub subheads (24px over a border) with forms flat beneath them, lists and tables in a box, and the danger zone in a red-bordered box with full-width rows. Fields follow GitHub's form groups in all three ways Forgejo writes them: the label on its own line, 440x32 inputs with GitHub's inset shadow and accent focus ring, a 32px select on the button surface, 12px muted notes, and 32px buttons with 500-weight labels. Checkboxes and radios take GitHub's design: the browser's 13px box in a 20px gutter, a semibold title beside it and the note beneath. Forgejo's checkbox markup stays (its scripts rely on it); a field label in front of a checkbox becomes the title and the checkbox's label its note, as in GitHub's feature list, and radio rows become one choice per line. Repository Template and Visibility use a shared checkbox component with Forgejo's descriptions as notes. Settings keep green primary buttons as on GitHub. Lists follow GitHub's Box: the rows with content draw the box, so the description rows Forgejo puts first become flat paragraphs above it; tables are boxed on their own, add forms sit flat below in one row, and empty lists show GitHub's empty state (a shared blankslate component) in collaborators, protected branches and tags, deploy keys, secrets, variables, runners, blocked users, push mirrors, package cleanup rules and authorized integrations. The shared webhook list becomes a description with box rows. Mirror settings, tag protection and the repository indexers are restructured: description, then the list or empty state, then the form or GitHub-style action rows. Repository settings drop the repository heading, as on GitHub. Personal and site administration settings get GitHub's context header above the nav (avatar, name and login, or the site administration icon). The org settings rules that duplicated this move into the shared component. Co-Authored-By: Claude Opus 5.5 --- components/common/settings/blankslate.tmpl | 6 + components/common/settings/checkbox.tmpl | 9 + components/common/settings/context.tmpl | 10 + components/common/settings/settings.css | 953 ++++++++++++++++++ styles/components/setting.ts | 12 +- styles/pages/organization.css | 41 - templates/admin/layout_head.tmpl | 16 + templates/admin/navbar.tmpl | 130 +++ templates/base/component_assets.tmpl | 1 + templates/org/settings/layout_head.tmpl | 14 + templates/org/settings/navbar.tmpl | 61 ++ templates/org/settings/options.tmpl | 109 ++ .../package/shared/cleanup_rules/list.tmpl | 57 ++ templates/repo/settings/branches.tmpl | 78 ++ templates/repo/settings/collaboration.tmpl | 176 ++++ templates/repo/settings/deploy_keys.tmpl | 86 ++ templates/repo/settings/layout_head.tmpl | 14 + templates/repo/settings/navbar.tmpl | 89 ++ templates/repo/settings/options.tmpl | 787 +++++++++++++++ templates/repo/settings/tags.tmpl | 119 +++ .../repo/settings/webhook/base_list.tmpl | 33 + templates/shared/actions/runner_list.tmpl | 143 +++ templates/shared/actions/secrets_list.tmpl | 130 +++ templates/shared/actions/variables_list.tmpl | 103 ++ templates/shared/blocked_users_list.tmpl | 28 + .../settings/authorized_integrations.tmpl | 67 ++ templates/user/settings/keys_gpg.tmpl | 129 +++ templates/user/settings/keys_ssh.tmpl | 128 +++ templates/user/settings/layout_head.tmpl | 18 + templates/user/settings/navbar.tmpl | 72 ++ templates/user/settings/profile.tmpl | 151 +++ 31 files changed, 3719 insertions(+), 51 deletions(-) create mode 100644 components/common/settings/blankslate.tmpl create mode 100644 components/common/settings/checkbox.tmpl create mode 100644 components/common/settings/context.tmpl create mode 100644 components/common/settings/settings.css create mode 100644 templates/admin/layout_head.tmpl create mode 100644 templates/admin/navbar.tmpl create mode 100644 templates/org/settings/layout_head.tmpl create mode 100644 templates/org/settings/navbar.tmpl create mode 100644 templates/org/settings/options.tmpl create mode 100644 templates/package/shared/cleanup_rules/list.tmpl create mode 100644 templates/repo/settings/branches.tmpl create mode 100644 templates/repo/settings/collaboration.tmpl create mode 100644 templates/repo/settings/deploy_keys.tmpl create mode 100644 templates/repo/settings/layout_head.tmpl create mode 100644 templates/repo/settings/navbar.tmpl create mode 100644 templates/repo/settings/options.tmpl create mode 100644 templates/repo/settings/tags.tmpl create mode 100644 templates/repo/settings/webhook/base_list.tmpl create mode 100644 templates/shared/actions/runner_list.tmpl create mode 100644 templates/shared/actions/secrets_list.tmpl create mode 100644 templates/shared/actions/variables_list.tmpl create mode 100644 templates/shared/blocked_users_list.tmpl create mode 100644 templates/user/settings/authorized_integrations.tmpl create mode 100644 templates/user/settings/keys_gpg.tmpl create mode 100644 templates/user/settings/keys_ssh.tmpl create mode 100644 templates/user/settings/layout_head.tmpl create mode 100644 templates/user/settings/navbar.tmpl create mode 100644 templates/user/settings/profile.tmpl diff --git a/components/common/settings/blankslate.tmpl b/components/common/settings/blankslate.tmpl new file mode 100644 index 00000000..46bf7944 --- /dev/null +++ b/components/common/settings/blankslate.tmpl @@ -0,0 +1,6 @@ +{{/* GitHub's empty state in settings: a bordered box with a centred semibold title and an optional muted line. Title + is text; Description may be rendered HTML. */}} +
+

{{.Title}}

+ {{if .Description}}

{{.Description}}

{{end}} +
diff --git a/components/common/settings/checkbox.tmpl b/components/common/settings/checkbox.tmpl new file mode 100644 index 00000000..ef634520 --- /dev/null +++ b/components/common/settings/checkbox.tmpl @@ -0,0 +1,9 @@ +{{/* GitHub's settings checkbox: the box beside a semibold title, with a muted note beneath the title. Name, ID, Checked, + Disabled and Value describe the input; Title and Note are text (Note may be rendered HTML); Tooltip explains a disabled + or risky choice; Extra is rendered HTML placed after the note, such as a hidden input or a warning. */}} +
+ + + {{if .Note}}

{{.Note}}

{{end}} + {{if .Extra}}{{.Extra}}{{end}} +
diff --git a/components/common/settings/context.tmpl b/components/common/settings/context.tmpl new file mode 100644 index 00000000..c4dd6844 --- /dev/null +++ b/components/common/settings/context.tmpl @@ -0,0 +1,10 @@ +{{/* GitHub's settings context: who or what these settings belong to, above the settings nav. Avatar is rendered HTML + (a user's avatar), Icon an octicon name when there is none. Link and LinkLabel add the button on the right. */}} +
+ {{if .Avatar}}{{.Avatar}}{{else}}{{svg .Icon 24}}{{end}} +
+

{{.Title}}{{if .Login}} ({{.Login}}){{end}}

+

{{.Subtitle}}

+
+ {{if .Link}}{{svg .LinkIcon 16}}{{.LinkLabel}}{{end}} +
diff --git a/components/common/settings/settings.css b/components/common/settings/settings.css new file mode 100644 index 00000000..e6f0f0fa --- /dev/null +++ b/components/common/settings/settings.css @@ -0,0 +1,953 @@ +/* GitHub's settings layout, shared by repository, personal, organization and site administration settings. The + area layouts mark their container with .theme-settings; Forgejo's own menu and form markup stays underneath. */ + +/* Context header: who or what the settings belong to. */ +.theme-settings-context { + display: flex; + align-items: center; + gap: 8px; + margin: 24px 0 16px; + & > img, + & .theme-settings-context-icon { + flex: none; + width: 48px; + height: 48px; + border-radius: 50%; + } + & .theme-settings-context-icon { + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid var(--color-light-border); + background: var(--color-box-header); + color: var(--color-text-light-1); + } + & > .button > .svg { + color: var(--color-text-light-1); + } +} + +.theme-settings-context-title { + flex: 1; + min-width: 0; + & h1 { + margin: 0; + font-size: 20px; + font-weight: 600; + line-height: 30px; + overflow-wrap: anywhere; + } + & h1 > span, + & p { + color: var(--color-text-light-1); + } + & p { + margin: 0; + font-size: 14px; + line-height: 21px; + } +} + +/* Columns: a 256px nav and the page, 40px apart. */ +.ui.container.flex-container.theme-settings { + gap: 40px; + margin-top: 24px; +} + +.theme-settings-context-container + .ui.container.flex-container.theme-settings { + margin-top: 0; +} + +/* Nav: GitHub's action list with an icon per page, group labels and a blue bar beside the current page. */ +.theme-settings > .flex-container-nav { + width: 256px; + & > .ui.fluid.vertical.menu { + border: 0; + background: transparent; + box-shadow: none; + } + & > .ui.vertical.menu { + & > .item:not(details), + & > details.item > summary, + & > details.item > .menu > .item { + position: relative; + display: flex; + align-items: center; + gap: 8px; + min-height: 33px; + margin: 0; + padding: 6px 8px; + border: 0; + border-radius: var(--border-radius); + background: transparent; + color: var(--color-text); + font-size: 14px; + font-weight: 400; + line-height: 21px; + &:hover { + background: var(--github-control-transparent-bgColor-hover); + color: var(--color-text); + } + &:focus-visible { + outline: 2px solid var(--github-fgColor-accent); + outline-offset: -2px; + } + } + & > details.item { + display: block; + width: 100%; + padding: 0; + background: transparent; + & > summary { + cursor: pointer; + } + & > .menu { + margin: 0; + padding: 0; + } + /* Pages inside a group line up with their group's label, as on GitHub. */ + & > .menu > .item { + padding-left: 32px; + } + } + & .item > .svg, + & summary > .svg:first-child { + flex: none; + color: var(--color-text-light-1); + } + & > .item.active, + & > details.item > .menu > .item.active { + background: var(--github-control-transparent-bgColor-active); + font-weight: 600; + &::before { + content: ""; + /* Fomantic hides ::before on nested menu items with a more specific rule. */ + display: block !important; + position: absolute; + top: 4px; + left: -8px; + width: 4px; + height: 24px; + border-radius: var(--border-radius); + background: var(--github-bgColor-accent-emphasis); + } + } + } + & > .ui.fluid.vertical.menu > details.item > summary::after { + flex: none; + margin-left: auto; + color: var(--color-text-light-1); + } +} + +.theme-settings-group, +.theme-settings-separator { + margin: 8px 0 0; + border-top: 1px solid color-mix(in srgb, var(--color-light-border) 70%, transparent); +} + +.theme-settings-group { + padding: 14px 8px 6px; + color: var(--color-text-light-1); + font-size: 12px; + font-weight: 600; + line-height: 19.5px; +} + +.theme-settings-separator { + margin-bottom: 8px; +} + +/* The page side is anchored on the page structure, which outranks the theme's older boxed style for settings + content. */ +.page-content > .ui.container.flex-container.theme-settings > .flex-container-main { + min-width: 0; + + /* Sections: GitHub's subhead, a 24px title over a border, with forms flat beneath it. Lists and tables keep a + box, and the danger zone gets GitHub's red-bordered box. */ + & .ui.top.attached.header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin: 0 0 16px; + padding: 0 0 8px; + border: 0 !important; + border-bottom: 1px solid color-mix(in srgb, var(--color-light-border) 70%, transparent) !important; + border-radius: 0; + background: transparent !important; + color: var(--color-text); + font-size: 24px; + font-weight: 400; + line-height: 36px; + /* Buttons in a subhead are GitHub's small buttons: 28px, 12px labels. */ + & .ui.button, + & .button { + min-height: 28px; + padding: 4px 12px; + font-size: 12px; + font-weight: 500; + line-height: 18px; + } + & > :is(.ui.right, .right) { + display: flex; + gap: 8px; + margin-left: auto; + font-size: 14px; + line-height: 20px; + } + } + & .ui.attached.segment ~ .ui.top.attached.header, + & .ui.attached.segment ~ * .ui.top.attached.header { + margin-top: 40px; + } + & .ui.attached.segment { + margin: 0; + padding: 0; + border: 0 !important; + border-radius: 0; + background: transparent; + box-shadow: none; + /* GitHub's Box: tables are boxed, so a description or an add form beside them stays flat. */ + & > table, + & > form > table { + margin: 0 0 16px; + border: 1px solid var(--color-light-border); + border-radius: var(--border-radius); + background: var(--color-box-body); + border-collapse: separate; + border-spacing: 0; + overflow: hidden; + } + & > :last-child { + margin-bottom: 0; + } + } + /* In lists the box is drawn by the rows with content, so a row Forgejo uses for the description stays a flat + paragraph above the box, and a list with only its description shows no empty box. Rows carry the padding, so + separators span the box. */ + & .ui.attached.segment:not(.error) > .flex-list { + margin: 0 0 16px; + &:last-child { + margin-bottom: 0; + } + & > .flex-item { + padding: 16px; + } + /* A row's actions stay side by side, also on phones. */ + & > .flex-item > .flex-item-trailing { + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + } + & > .flex-item:not(:has(> .flex-item-main)) { + padding: 0 0 16px; + border: 0; + font-size: 14px; + line-height: 21px; + } + & > .flex-item:has(> .flex-item-main) { + border: 1px solid var(--color-light-border); + border-radius: 0; + background: var(--color-box-body); + &:not(:has(+ .flex-item:has(> .flex-item-main))) { + border-bottom-right-radius: var(--border-radius); + border-bottom-left-radius: var(--border-radius); + } + } + & > .flex-item:has(> .flex-item-main) + .flex-item:has(> .flex-item-main) { + margin-top: -1px; + } + & > .flex-item:has(> .flex-item-main):not(.flex-item:has(> .flex-item-main) + *) { + border-top-left-radius: var(--border-radius); + border-top-right-radius: var(--border-radius); + } + } + /* Fomantic lists (emails, personal repositories, git hooks) get the same box rows; what is not an item, such as the + emails' description, stays a flat paragraph above. A list wrapping a form (the theme picker) is no list. */ + & .ui.attached.segment > .ui.list:has(> form) { + margin: 0; + & > .item { + margin: 0 0 16px; + padding: 0; + } + } + & .ui.attached.segment:not(.error) > .ui.list:not(:has(> form)) { + margin: 0; + padding: 0; + & > :not(.item) { + margin: 0 0 16px; + font-size: 14px; + line-height: 21px; + } + & > .item { + display: flow-root; + margin: 0; + padding: 16px; + border: 1px solid var(--color-light-border); + background: var(--color-box-body); + &:first-of-type { + border-top-left-radius: var(--border-radius); + border-top-right-radius: var(--border-radius); + } + &:last-of-type { + border-bottom-left-radius: var(--border-radius); + border-bottom-right-radius: var(--border-radius); + } + & + .item { + margin-top: -1px; + } + &::before { + display: none; + } + } + } + /* An add form below its list (Forgejo's bottom attached segment) sits 16px under the box. */ + & .ui.attached.segment + .ui.bottom.attached.segment { + margin-top: 16px; + } + /* The danger zone's rows sit in a red box; a deletion form (an account, an organization) stays flat under its red + heading, its warning a danger flash. */ + & .ui.attached.error.segment { + padding: 0; + border: 0 !important; + background: transparent; + &:has(> .flex-list) { + border: 1px solid color-mix(in srgb, var(--color-red) 40%, transparent) !important; + border-radius: var(--border-radius); + background: var(--color-box-body); + } + & > .flex-list { + margin: 0; + border: 0; + background: transparent; + } + & .flex-item-title { + font-size: 14px; + font-weight: 600; + } + & > .ui.red.message { + margin: 0 0 16px; + padding: 16px; + border: 1px solid color-mix(in srgb, var(--color-red) 40%, transparent); + border-radius: var(--border-radius); + background: color-mix(in srgb, var(--color-red) 10%, transparent); + box-shadow: none; + color: var(--color-text); + font-size: 14px; + & .svg { + color: var(--color-red); + } + } + } + + /* GitHub's box rows for actions (the indexers): what it is on the left, the button on the right. */ + & .flex-list.theme-settings-rows { + margin: 16px 0 0; + border: 1px solid var(--color-light-border); + border-radius: var(--border-radius); + background: var(--color-box-body); + & > .flex-item { + align-items: center; + padding: 16px; + } + & .flex-item-title { + font-size: 14px; + font-weight: 600; + } + & .flex-item-body { + color: var(--color-text-light-1); + font-size: 12px; + } + } + + /* Add forms with a search field (collaborators, teams): the field and its button in one row. */ + & .ui.attached.segment > form.ui.form:has(> .ui.search) { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + & > .ui.search { + width: 240px; + max-width: 100%; + } + & > .ui.search > input { + width: 100%; + } + } + + /* A control and its button in one row (the default branch). */ + & form.ui.form.theme-settings-inline-form { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + & > .ui.dropdown { + width: 320px; + max-width: 100%; + } + } + + /* A form of one field and its button (adding an email) puts the button beside the input, as on GitHub. */ + & form.ui.form:has(> .field:first-child + .ui.button:last-child) { + display: flex; + flex-wrap: wrap; + align-items: flex-end; + gap: 8px; + & > .field { + flex: 0 1 440px; + margin: 0; + } + } + + /* A section's description above its box, as on GitHub. */ + & .theme-settings-description { + margin: 0 0 16px; + font-size: 14px; + line-height: 21px; + } + + /* GitHub's empty state (components/common/settings/blankslate.tmpl). */ + & .theme-settings-blankslate { + margin: 0 0 16px; + padding: 32px; + border: 1px solid var(--color-light-border); + border-radius: var(--border-radius); + background: var(--color-box-body); + text-align: center; + & h3 { + margin: 0; + font-size: 16px; + font-weight: 600; + line-height: 24px; + } + & p { + margin: 4px 0 0; + color: var(--color-text-light-1); + font-size: 14px; + line-height: 21px; + } + } + + /* GitHub's summary row (a repository's visibility): an icon in a bordered square, a semibold title over a muted + line, and an action on the right. */ + & .theme-settings-summary { + display: flex; + align-items: center; + gap: 12px; + margin: 0 0 8px; + padding: 0 0 16px; + & > .theme-settings-summary-main { + display: flex; + flex: 1; + flex-direction: column; + min-width: 0; + & > strong { + font-size: 14px; + font-weight: 600; + line-height: 21px; + } + & > span { + color: var(--color-text-light-1); + font-size: 14px; + line-height: 21px; + } + } + } + & .theme-settings-summary-icon, + & .theme-settings-team-icon { + display: inline-flex; + flex: none; + align-items: center; + justify-content: center; + border: 1px solid var(--color-light-border); + border-radius: var(--border-radius); + color: var(--color-text-light-1); + } + & .theme-settings-summary-icon { + width: 50px; + height: 50px; + } + & .theme-settings-team-icon { + width: 32px; + height: 32px; + } + + /* GitHub's bordered panel ("Direct access"): a semibold title with its icon on the right, and a muted line. */ + & .theme-settings-panel { + margin: 0 0 32px; + padding: 16px; + border: 1px solid color-mix(in srgb, var(--color-light-border) 70%, transparent); + border-radius: var(--border-radius); + & > .theme-settings-panel-title { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 14px; + font-weight: 600; + line-height: 21px; + & > .svg { + color: var(--color-text-light-1); + } + } + & > p { + margin: 8px 0 0; + color: var(--color-text-light-1); + font-size: 12px; + line-height: 18px; + & > strong { + color: var(--color-text); + } + } + } + + /* A titled part inside a section ("Manage access"): a 16px semibold title with its action on the right. */ + & .theme-settings-subsection { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + min-height: 32px; + margin: 0 0 16px; + * + & { + margin-top: 32px; + } + & > h3 { + margin: 0; + font-size: 16px; + font-weight: 600; + line-height: 24px; + } + } + + /* An empty state with an illustration icon is GitHub's spacious one: a larger title and an action below. */ + & .theme-settings-blankslate:has(> .svg) { + & > .svg { + color: var(--color-primary); + } + & > h3 { + margin: 16px 0; + font-size: 20px; + line-height: 30px; + } + } + + /* GitHub's two columns (public profile): the form, and a 200px column on the right for the picture. */ + & .ui.attached.segment.theme-settings-columns { + display: grid; + grid-template-columns: minmax(0, 1fr) 200px; + gap: 32px; + align-items: start; + } + & .theme-settings-aside { + & > h3 { + margin: 0 0 8px; + font-size: 14px; + font-weight: 600; + line-height: 21px; + } + /* Forgejo caps avatar images in forms; the picture here is GitHub's 200px circle. */ + & > img.theme-settings-avatar { + display: block; + width: 200px !important; + height: 200px !important; + margin: 0 0 16px; + border-radius: 50%; + box-shadow: 0 0 0 1px var(--color-light-border); + } + & .field.tw-pl-4 { + padding-left: 20px !important; + } + & input:is([type="file"], [type="text"], :not([type])) { + width: 100%; + max-width: 100%; + } + & .button-sequence { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 8px; + } + } + /* Forgejo's form groups ("About you", "Privacy") read as small section titles. */ + & .ui.form fieldset > legend { + margin: 0 0 8px; + padding: 0; + font-size: 16px; + font-weight: 600; + line-height: 24px; + } + & .ui.form fieldset + fieldset { + margin-top: 24px; + padding-top: 16px; + border-top: 1px solid color-mix(in srgb, var(--color-light-border) 70%, transparent); + } + + /* Buttons: GitHub's 32px controls with 500-weight labels, for Fomantic's .ui.button and Forgejo's newer .button. */ + & :is(.ui.button, .button:not(.ui)):not(.tiny, .mini, .compact, .icon) { + min-height: 32px; + padding: 5px 16px; + font-size: 14px; + font-weight: 500; + line-height: 20px; + } + + /* GitHub's settings checkbox (components/common/settings/checkbox.tmpl): the box in a 20px gutter beside a + semibold title, with the note beneath the title. */ + & .theme-settings-checkbox { + position: relative; + margin: 15px 0; + padding-left: 20px; + & > input[type="checkbox"] { + position: absolute; + top: 4px; + left: 0; + margin: 0; + } + & > label { + display: inline; + margin: 0; + color: var(--color-text); + font-size: 14px; + font-weight: 600; + line-height: 21px; + cursor: pointer; + } + & > input:disabled + label { + color: var(--color-text-light-1); + cursor: default; + } + } + & .theme-settings-checkbox-note { + margin: 0; + color: var(--color-text-light-1); + font-size: 12px; + line-height: 18px; + } +} + +/* Forms: GitHub's form groups. The label sits on its own line (14px semibold, 6px above the control), controls are + 32px and no wider than 440px with an inset shadow and an accent focus ring, notes are muted 12px. Forgejo writes + fields as .field with a label beside the control, or as a label wrapping its control inside a fieldset or straight + in the form; all get the same look. */ +.page-content > .ui.container.flex-container.theme-settings > .flex-container-main .ui.form { + & .field, + & fieldset > label, + & > label { + margin: 0 0 15px; + } + & .field > label, + & fieldset > label, + & > label { + display: block; + color: var(--color-text); + font-size: 14px; + font-weight: 600; + line-height: 21px; + } + & .field > label { + margin-bottom: 6px; + } + & + :is(.field, fieldset > label) + > :is( + input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"], [type="color"]), + select, + textarea, + .ui.selection.dropdown + ), + & + > label + > :is( + input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"], [type="color"]), + select, + textarea, + .ui.selection.dropdown + ) { + display: block; + width: 100%; + max-width: 440px; + font-weight: 400; + } + & + fieldset + > label + > :is( + input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"], [type="color"]), + select, + textarea, + .ui.selection.dropdown + ) { + margin-top: 6px; + } + & + :is( + input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"], [type="color"]), + select, + textarea + ) { + border: 1px solid var(--color-light-border); + border-radius: var(--border-radius); + background: var(--color-input-background); + box-shadow: inset 0 1px 0 rgb(1 4 9 / 24%); + color: var(--color-text); + font-size: 14px; + &:focus { + border-color: var(--github-bgColor-accent-emphasis); + outline: none; + box-shadow: inset 0 0 0 1px var(--github-bgColor-accent-emphasis); + } + } + & input:not([type="checkbox"], [type="radio"], [type="file"], [type="hidden"], [type="color"]) { + height: 32px; + min-height: 32px; + padding: 5px 12px; + line-height: 20px; + } + & textarea { + padding: 8px 12px; + line-height: 21px; + } + + /* Selects look like GitHub's: the default button surface with a caret. Fomantic sizes its selection dropdown with + a more specific rule. */ + & select, + & .ui.selection.dropdown { + min-height: 32px; + padding: 5px 24px 5px 12px; + border: 1px solid var(--color-light-border); + border-radius: var(--border-radius); + background-color: var(--color-button); + box-shadow: inset 0 1px 0 rgb(1 4 9 / 24%); + font-size: 14px; + line-height: 20px; + } + /* Fields wrapped in Fomantic's search or input containers get the same 440px limit. */ + & .field > :is(.ui.search, .ui.input) { + max-width: 440px; + & .ui.input, + & input { + width: 100%; + } + } + /* Multiple-choice dropdowns (allowed users and teams) are 32px until they hold chosen items. */ + & .ui.multiple.selection.dropdown { + min-height: 32px !important; + padding: 2px 24px 2px 8px !important; + & > input.search, + & > .default.text { + margin: 3px 0 3px 4px; + padding: 0; + line-height: 20px; + } + } + & .ui.selection.dropdown:not(.multiple) { + padding: 5px 24px 5px 12px !important; + line-height: 20px !important; + & > .dropdown.icon { + right: 8px; + } + } + + & :is(.help, p.help) { + display: block; + margin: 4px 0 2px; + color: var(--color-text-light-1); + font-size: 12px; + font-weight: 400; + line-height: 18px; + } + + /* Checkboxes and radios: the browser's own 13px box in a 20px gutter, a semibold title beside it and any note + beneath the title. Fomantic's drawn box and check mark go. */ + & input[type="checkbox"] { + appearance: auto; + flex: none; + width: 13px; + height: 13px; + margin: 4px 7px 0 0; + /* Forgejo zeroes the top margin with !important; the box lines up with the 21px title line. */ + margin-block-start: 4px !important; + border-radius: 3px; + accent-color: var(--github-bgColor-accent-emphasis); + vertical-align: top; + } + /* Forgejo draws its own check mark as the input's ::after; the browser's box draws it instead. */ + & input:is([type="checkbox"], [type="radio"])::after { + display: none; + } + /* A label wrapping its checkbox (the hidden comment types): the box in the gutter, the text beside it, the note + under the text. */ + & label:has(> input[type="checkbox"]) { + display: grid; + grid-template-columns: 20px minmax(0, 1fr); + align-items: start; + font-weight: 600; + & > input[type="checkbox"] { + grid-column: 1; + grid-row: 1; + margin: 4px 0 0; + } + & > :not(input) { + grid-column: 2; + } + & > .help { + display: block; + } + & + .help { + margin-left: 20px; + } + } + & .ui.checkbox { + display: grid; + grid-template-columns: 20px minmax(0, 1fr); + align-items: start; + & > input { + position: static; + grid-column: 1; + grid-row: 1; + width: 13px; + height: 13px; + margin: 4px 0 0; + opacity: 1; + } + & > label { + grid-column: 2; + grid-row: 1; + margin: 0; + padding: 0; + color: var(--color-text); + font-size: 14px; + font-weight: 600; + line-height: 21px; + &::before, + &::after { + display: none; + } + } + &.disabled > label { + color: var(--color-text-light-1); + } + /* Notes Forgejo puts inside the checkbox (the signing trust models) sit under the title, not in the box's + gutter. */ + & > :not(input, label) { + grid-column: 2; + margin: 0; + } + } + + /* A field that only shows a value (Forgejo's repository size) keeps label and value on one line. */ + & .inline.field:not(:has(input, select, textarea, .ui.checkbox, .ui.dropdown)) { + display: flex; + align-items: baseline; + gap: 8px; + & > label { + margin: 0; + } + } + /* Forgejo separates some labels from their choices with a line break; the field spacing does that. */ + & .field > br { + display: none; + } + + /* Radio groups Forgejo lays out in a row (.inline.fields) become GitHub's list: the group label above, one choice + per line. */ + & .inline.fields { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + margin: 0 0 15px; + & > label { + margin: 0; + color: var(--color-text); + font-size: 14px; + font-weight: 600; + line-height: 21px; + } + & > .field { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 0 8px; + margin: 0; + padding: 0; + } + } + + /* Forgejo's checkbox fields join one grid without changing their markup (scripts rely on it): the box in the + gutter, the title beside it, notes beneath. A field label in front of the checkbox (Forgejo's "Issues" before + "Enable repository issues") becomes the title and the checkbox's own label its note, as in GitHub's feature + list. */ + & .inline.field:has(> label:first-child + .ui.checkbox), + & .field:has(> .ui.checkbox:first-child) { + display: grid; + grid-template-columns: 20px minmax(0, 1fr); + align-items: start; + margin: 15px 0; + & > .ui.checkbox { + display: contents; + } + & > *:not(.ui.checkbox) { + grid-column: 2; + } + & > .help { + margin: 0; + } + } + & .inline.field:has(> label:first-child + .ui.checkbox) { + & > label:first-child { + grid-row: 1; + width: auto; + margin: 0; + padding: 0; + } + & > .ui.checkbox > label { + grid-row: 2; + color: var(--color-text-light-1); + font-size: 12px; + font-weight: 400; + line-height: 18px; + } + } +} + +/* Choices inside a radio group sit 8px apart; the checkbox-field margin above does not apply to them. */ +.page-content + > .ui.container.flex-container.theme-settings + > .flex-container-main + .ui.form + .inline.fields + > .field:has(> .ui.checkbox) { + margin: 0; +} + +@media (max-width: 767.98px) { + .ui.container.flex-container.theme-settings { + gap: 24px; + } + + .theme-settings > .flex-container-nav { + width: auto; + } + + .page-content + > .ui.container.flex-container.theme-settings + > .flex-container-main + .ui.attached.segment.theme-settings-columns { + grid-template-columns: minmax(0, 1fr); + } + + .page-content + > .ui.container.flex-container.theme-settings + > .flex-container-main + .ui.form + .field + > :is(input, select, textarea, .ui.selection.dropdown) { + max-width: none; + } + + .theme-settings-context { + flex-wrap: wrap; + } +} diff --git a/styles/components/setting.ts b/styles/components/setting.ts index 21567908..81f6527d 100644 --- a/styles/components/setting.ts +++ b/styles/components/setting.ts @@ -18,11 +18,7 @@ */ import { css, cssCombine, cssStyle, themeVars } from "@lutinglt/gitea-github-theme/core"; -import { - basicButtonStyle, - primaryButtonHoverStyle, - primaryButtonStyle, -} from "@lutinglt/gitea-github-theme/styles/common"; +import { primaryButtonHoverStyle, primaryButtonStyle } from "@lutinglt/gitea-github-theme/styles/common"; const tinyStyle = cssStyle({ color: themeVars.github.themeExtra.button.primary.fgColor.accent, @@ -38,15 +34,11 @@ const tinyHoverStyle = cssStyle({ // 设置界面下的按钮 const button = css` - /* 不包含管理员的设置界面 */ + /* Settings outside site administration keep GitHub's green primary buttons (Update profile, Add key). */ .user-main-content, .repo-setting-content, .user-setting-content, .org-setting-content { - /* 主色调按钮替换为普通按钮 */ - .ui.primary.button { - ${basicButtonStyle} - } /* 迷你按钮替换为自定义的主色调按钮 (例: SSH 验证按钮) */ .ui.primary.button.tiny { ${tinyStyle} diff --git a/styles/pages/organization.css b/styles/pages/organization.css index 0d276b81..49e09034 100644 --- a/styles/pages/organization.css +++ b/styles/pages/organization.css @@ -320,39 +320,6 @@ font-size: 20px; } -.page-content.organization.settings .flex-container { - gap: 32px; -} - -.page-content.organization.settings .flex-container-nav { - width: 280px; -} - -.page-content.organization.settings .flex-container-main .org-setting-content > .ui.top.attached.header { - padding: 0 0 12px; - border: 0; - border-bottom: 1px solid var(--color-secondary); - background: transparent; - font-size: 24px; - font-weight: 400; -} - -.page-content.organization.settings .flex-container-main .org-setting-content > .ui.attached.segment { - padding: 24px 0; - /* The shared attached-segment theme uses an important border. */ - border: 0 !important; - background: transparent; -} - -.page-content.organization.settings.options .org-setting-content form { - max-width: 640px; -} - -.page-content.organization.settings.options .org-setting-content input:not([type="radio"]):not([type="checkbox"]), -.page-content.organization.settings.options .org-setting-content textarea { - background: var(--color-input-background); -} - .organization .list-header { margin-bottom: 16px; } @@ -402,14 +369,6 @@ .page-content.organization.members .org-member-row .actions { grid-column: 1 / -1; } - - .page-content.organization.settings .flex-container-nav { - width: auto; - } - - .page-content.organization.settings .flex-container { - gap: 24px; - } } .org-page-toolbar { diff --git a/templates/admin/layout_head.tmpl b/templates/admin/layout_head.tmpl new file mode 100644 index 00000000..26795fb5 --- /dev/null +++ b/templates/admin/layout_head.tmpl @@ -0,0 +1,16 @@ +{{template "base/head" .ctxData}} +
+
+ {{template "components/common/settings/context" dict "Icon" "octicon-server" "Title" (ctx.Locale.Tr "admin_panel") "Subtitle" AppName}} +
+
+ {{template "admin/navbar" .ctxData}} +
+ {{template "base/alert" .ctxData}} + {{/* block: admin-setting-content */}} + +{{if false}}{{/* to make html structure "likely" complete to prevent IDE warnings */}} +
+
+
+{{end}} diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl new file mode 100644 index 00000000..d8400d35 --- /dev/null +++ b/templates/admin/navbar.tmpl @@ -0,0 +1,130 @@ +{{/* Forgejo's admin nav with GitHub's icon per top-level page; the site administration header above it names the area. */}} +
+ +
diff --git a/templates/base/component_assets.tmpl b/templates/base/component_assets.tmpl index d408c645..399b3ba2 100644 --- a/templates/base/component_assets.tmpl +++ b/templates/base/component_assets.tmpl @@ -9,6 +9,7 @@ + diff --git a/templates/org/settings/layout_head.tmpl b/templates/org/settings/layout_head.tmpl new file mode 100644 index 00000000..1c88d8a5 --- /dev/null +++ b/templates/org/settings/layout_head.tmpl @@ -0,0 +1,14 @@ +{{template "base/head" .ctxData}} +
+ {{template "org/header" .ctxData}} +
+ {{template "org/settings/navbar" .ctxData}} +
+ {{template "base/alert" .ctxData}} + {{/* block: org-setting-content */}} + +{{if false}}{{/* to make html structure "likely" complete to prevent IDE warnings */}} +
+
+
+{{end}} diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl new file mode 100644 index 00000000..0f6a9bda --- /dev/null +++ b/templates/org/settings/navbar.tmpl @@ -0,0 +1,61 @@ +{{/* GitHub's organization settings nav: an icon per page, grouped under Access, Code, planning, and automation, + and Integrations. Forgejo has no strings for the group names. */}} + diff --git a/templates/org/settings/options.tmpl b/templates/org/settings/options.tmpl new file mode 100644 index 00000000..6ddc00cc --- /dev/null +++ b/templates/org/settings/options.tmpl @@ -0,0 +1,109 @@ +{{/* GitHub's organization profile: the form on the left, the profile picture and its upload in a column on the right. */}} +{{template "org/settings/layout_head" (dict "ctxData" . "pageClass" "organization settings options")}} +
+

+ {{ctx.Locale.Tr "org.settings.options"}} +

+
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ + + {{ctx.Locale.Tr "form.website.valid_url_schemes" (StringUtils.Join .ValidSiteURLSchemes ", ")}} +
+
+ + +
+ +
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+
+ + {{if .SignedUser.IsAdmin}} +
+ +
+ + +

{{ctx.Locale.Tr "admin.users.max_repo_creation_desc"}}

+
+ {{end}} + +
+ +
+
+ + +
+
+{{template "org/settings/layout_footer" .}} diff --git a/templates/package/shared/cleanup_rules/list.tmpl b/templates/package/shared/cleanup_rules/list.tmpl new file mode 100644 index 00000000..c81ab683 --- /dev/null +++ b/templates/package/shared/cleanup_rules/list.tmpl @@ -0,0 +1,57 @@ +{{/* Forgejo's package cleanup rules with GitHub's empty state. */}} +

+ {{ctx.Locale.Tr "packages.owner.settings.cleanuprules.title"}} + +

+
+
+ {{range .CleanupRules}} +
+
+ {{svg .Type.SVGName 32}} +
+
+ +
+

{{if .Enabled}}{{ctx.Locale.Tr "enabled"}}{{else}}{{ctx.Locale.Tr "disabled"}}{{end}}

+
+ {{if .KeepCount}} +
+

{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.count"}}:

{{if eq .KeepCount 1}}{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.count.1"}}{{else}}{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.count.n" .KeepCount}}{{end}} +
+ {{end}} + {{if .KeepPattern}} +
+

{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.keep.pattern"}}:

{{StringUtils.EllipsisString .KeepPattern 100}} +
+ {{end}} + {{if .RemoveDays}} +
+

{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.remove.days"}}:

{{ctx.Locale.Tr "tool.days" .RemoveDays}} +
+ {{end}} + {{if .RemovePattern}} +
+

{{ctx.Locale.Tr "packages.owner.settings.cleanuprules.remove.pattern"}}:

{{StringUtils.EllipsisString .RemovePattern 100}} +
+ {{end}} +
+ +
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "packages.owner.settings.cleanuprules.none")}} + {{end}} +
+
diff --git a/templates/repo/settings/branches.tmpl b/templates/repo/settings/branches.tmpl new file mode 100644 index 00000000..a7b3c828 --- /dev/null +++ b/templates/repo/settings/branches.tmpl @@ -0,0 +1,78 @@ +{{/* Forgejo's branch settings with GitHub's description, inline default-branch form and empty state. */}} +{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings edit")}} +
+ {{if .Repository.IsArchived}} +
+ {{ctx.Locale.Tr "repo.settings.archive.branchsettings_unavailable"}} +
+ {{else}} +

+ {{ctx.Locale.Tr "repo.default_branch"}} +

+
+

+ {{ctx.Locale.Tr "repo.settings.default_branch_desc"}} +

+
+ + {{if not .Repository.IsEmpty}} + + + {{end}} +
+
+ +

+ {{ctx.Locale.Tr "repo.settings.protected_branch"}} + +

+ +
+ {{if .ProtectedBranches}} +
+ {{range .ProtectedBranches}} +
+
+
+
{{.RuleName}}
+
+
+
+ {{ctx.Locale.Tr "repo.settings.edit_protected_branch"}} + +
+
+ {{end}} +
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "repo.settings.no_protected_branch")}} + {{end}} +
+ {{end}} +
+ + + +{{template "repo/settings/layout_footer" .}} diff --git a/templates/repo/settings/collaboration.tmpl b/templates/repo/settings/collaboration.tmpl new file mode 100644 index 00000000..0bbd1099 --- /dev/null +++ b/templates/repo/settings/collaboration.tmpl @@ -0,0 +1,176 @@ +{{/* GitHub's "Collaborators and teams": the repository's visibility, a summary of direct access, then "Manage access" + with the people (and, for organization repositories, the teams) in a box or an empty state, added through a dialog. + Forgejo has no strings for the visibility sentences, "Direct access" and "Manage access". Forgejo's hooks stay: the + search box ids, the access-mode menu and the delete modal. */}} +{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings collaboration")}} +
+

+ {{ctx.Locale.Tr "repo.settings.collaboration"}} +

+
+
+ {{if .Repository.IsPrivate}}{{svg "octicon-lock" 16}}{{else}}{{svg "octicon-eye" 16}}{{end}} +
+ {{if .Repository.IsPrivate}}Private repository{{else}}Public repository{{end}} + {{if .Repository.IsPrivate}}{{ctx.Locale.Tr "repo.visibility_description"}}{{else}}This repository is public and visible to anyone.{{end}} +
+ Manage visibility +
+ +
+
Direct access {{svg "octicon-people" 16}}
+

{{len .Collaborators}} {{if eq (len .Collaborators) 1}}collaborator has{{else}}collaborators have{{end}} access to this repository.{{if .RepoOwnerIsOrganization}} {{len .Teams}} {{if eq (len .Teams) 1}}team has{{else}}teams have{{end}} access too.{{end}}

+
+ +
+

Manage access

+ {{if .Collaborators}}{{end}} +
+ {{if .Collaborators}} +
+ {{range .Collaborators}} +
+ +
+
+ {{template "shared/user/name" .}} +
+
+
+ + +
+
+ {{end}} +
+ {{else}} +
+ {{svg "octicon-people" 32}} +

{{ctx.Locale.Tr "repo.settings.collaboration.none"}}

+ +
+ {{end}} + + {{if .RepoOwnerIsOrganization}} + {{$allowedToChangeTeams := (or (.Org.RepoAdminChangeTeamAccess) (.Permission.IsOwner))}} +
+

{{ctx.Locale.Tr "repo.settings.teams"}}

+ {{if and $allowedToChangeTeams .Teams}}{{end}} +
+ {{if not $allowedToChangeTeams}} +

{{ctx.Locale.Tr "repo.settings.change_team_access_not_allowed"}}

+ {{end}} + {{if .Teams}} +
+ {{range $t, $team := .Teams}} +
+
+ {{svg "octicon-people" 16}} +
+
+ + {{.Name}} + +
+ {{svg "octicon-shield-lock"}} + {{if eq .AccessMode 1}}{{ctx.Locale.Tr "repo.settings.collaboration.read"}}{{else if eq .AccessMode 2}}{{ctx.Locale.Tr "repo.settings.collaboration.write"}}{{else if eq .AccessMode 3}}{{ctx.Locale.Tr "repo.settings.collaboration.admin"}}{{else if eq .AccessMode 4}}{{ctx.Locale.Tr "repo.settings.collaboration.owner"}}{{else}}{{ctx.Locale.Tr "repo.settings.collaboration.undefined"}}{{end}} +
+ {{if or (eq .AccessMode 1) (eq .AccessMode 2)}} + {{$first := true}} +
+ Sections: {{range $u, $unit := $.Units}}{{if and ($.Repo.UnitEnabled $.Context $unit.Type) ($team.UnitEnabled $.Context $unit.Type)}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{ctx.Locale.Tr $unit.NameKey}}{{end}}{{end}} {{if $first}}None{{end}} +
+ {{end}} +
+ {{if $allowedToChangeTeams}} +
+ +
+ {{end}} +
+ {{end}} +
+ {{else}} +
+ {{svg "octicon-people" 32}} +

No teams have access to this repository.

+ {{if $allowedToChangeTeams}}{{end}} +
+ {{end}} + {{end}} +
+
+ + +
+
{{ctx.Locale.Tr "repo.settings.add_collaborator"}}
+
+
+
+ + +
+
+
+ + +
+
+
+
+ +{{if .RepoOwnerIsOrganization}} + +
+
{{ctx.Locale.Tr "repo.settings.add_team"}}
+
+
+
+ + +
+
+
+ + +
+
+
+
+{{end}} + + + +{{template "repo/settings/layout_footer" .}} diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl new file mode 100644 index 00000000..f8eb0f4e --- /dev/null +++ b/templates/repo/settings/deploy_keys.tmpl @@ -0,0 +1,86 @@ +{{/* Forgejo's deploy keys with GitHub's empty state. */}} +{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings")}} +
+

+ {{ctx.Locale.Tr "repo.settings.deploy_keys"}} +
+ {{if not .DisableSSH}} + + {{else}} + + {{end}} +
+

+
+
+
+
+ {{ctx.Locale.Tr "repo.settings.deploy_key_desc"}} +
+
+ + +
+
+ + +
+
+
+ + + {{ctx.Locale.Tr "repo.settings.is_writable_info"}} +
+
+ + +
+
+ {{if .Deploykeys}} +
+ {{range .Deploykeys}} +
+
+ {{svg "octicon-key" 32}} +
+
+
{{.Name}}
+
+ {{.Fingerprint}} +
+
+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}} - {{ctx.Locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{ctx.Locale.Tr "settings.can_write_info"}} {{end}}

+
+
+
+ +
+
+ {{end}} +
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "repo.settings.no_deploy_keys")}} + {{end}} +
+
+ + + +{{template "repo/settings/layout_footer" .}} diff --git a/templates/repo/settings/layout_head.tmpl b/templates/repo/settings/layout_head.tmpl new file mode 100644 index 00000000..4905246f --- /dev/null +++ b/templates/repo/settings/layout_head.tmpl @@ -0,0 +1,14 @@ +{{template "base/head" .ctxData}} +
+ {{/* GitHub shows repository settings below the tabs only, without the repository heading. */}} +
+ {{template "repo/settings/navbar" .ctxData}} +
+ {{template "base/alert" .ctxData}} + {{/* block: repo-setting-content */}} + +{{if false}}{{/* to make html structure "likely" complete to prevent IDE warnings */}} +
+
+
+{{end}} diff --git a/templates/repo/settings/navbar.tmpl b/templates/repo/settings/navbar.tmpl new file mode 100644 index 00000000..c8dc9542 --- /dev/null +++ b/templates/repo/settings/navbar.tmpl @@ -0,0 +1,89 @@ +{{/* GitHub's repository settings nav: an icon per page, grouped under Access, Code and automation, and Security. + Forgejo has no strings for the group names. */}} +
+ +
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl new file mode 100644 index 00000000..025e1508 --- /dev/null +++ b/templates/repo/settings/options.tmpl @@ -0,0 +1,787 @@ +{{/* Forgejo's repository options with GitHub's settings checkboxes for Template and Visibility. */}} +{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings options")}} +
+

+ {{ctx.Locale.Tr "repo.settings.basic_settings"}} +

+
+
+ {{template "base/disable_form_autofill"}} + +
+ + +
+
+ + {{ctx.Locale.TrSize .Repository.Size}} +
+ {{/* GitHub's checkboxes: a semibold title with Forgejo's description as the note beneath it. */}} + {{template "components/common/settings/checkbox" dict "ID" "repo-template" "Name" "template" "Checked" .Repository.IsTemplate "Title" (ctx.Locale.Tr "repo.template_helper") "Note" (ctx.Locale.Tr "repo.template_description")}} + {{if not .Repository.IsFork}} + {{$forced := and (not .IsAdmin) $.ForcePrivate .Repository.IsPrivate}} + {{$visibilityNote := ctx.Locale.Tr "repo.visibility_description"}} + {{if .Repository.NumForks}}{{$visibilityNote = print $visibilityNote " " (ctx.Locale.Tr "repo.visibility_fork_helper")}}{{end}} + {{$keepPrivate := ""}} + {{if $forced}}{{$keepPrivate = HTMLFormat `` .Repository.IsPrivate}}{{end}} + {{template "components/common/settings/checkbox" dict "ID" "repo-private" "Name" "private" "Checked" .Repository.IsPrivate "Disabled" $forced "Title" (ctx.Locale.Tr "repo.visibility_helper") "Note" $visibilityNote "Tooltip" (and (not .Repository.IsPrivate) (gt .Repository.NumStars 0) (ctx.Locale.Tr "repo.stars_remove_warning")) "Extra" $keepPrivate}} + {{end}} +
+ + +
+
+ + + {{ctx.Locale.Tr "form.website.valid_url_schemes" (StringUtils.Join .ValidSiteURLSchemes ", ")}} +
+
+ +
+
+ +
+
+
+ + +
{{ctx.Locale.Tr "avatar.constraints_hint" (ctx.Locale.TrSize .MaxAvatarFileSize) .MaxAvatarWidth .MaxAvatarHeight}} +
+
+ + +
+
+
+ + {{if FederationEnabled}} +

+ {{ctx.Locale.Tr "repo.settings.federation_settings"}} +

+
+
+ +
+

{{ctx.Locale.Tr "repo.settings.federation_apapiurl"}}

+

{{.RepositoryAPActorID}}

+
+ + +
+
+ +
+
+
+ {{end}} + + {{/* These variables exist to make the logic in the Settings window easier to comprehend and are not used later on. */}} + {{$newMirrorsPartiallyEnabled := or (not .DisableNewPullMirrors) (not .DisableNewPushMirrors)}} + {{/* .Repository.IsMirror is not always reliable if the repository is not actively acting as a mirror because of errors. */}} + {{$showMirrorSettings := and (.Repository.UnitEnabled $.Context $.UnitTypeCode) (or $newMirrorsPartiallyEnabled .Repository.IsMirror .PullMirror .PushMirrors)}} + {{$newMirrorsEntirelyEnabled := and (not .DisableNewPullMirrors) (not .DisableNewPushMirrors)}} + {{$onlyNewPushMirrorsEnabled := and (not .DisableNewPushMirrors) .DisableNewPullMirrors}} + {{$onlyNewPullMirrorsEnabled := and .DisableNewPushMirrors (not .DisableNewPullMirrors)}} + {{$existingPushMirror := or .Repository.IsMirror .PushMirrors}} + {{$modifyBrokenPullMirror := and .Repository.IsMirror (not .PullMirror)}} + {{$isWorkingPullMirror := .PullMirror}} + + {{if $showMirrorSettings}} +

+ {{ctx.Locale.Tr "mirror_settings.header"}} +

+
+ {{if .Repository.IsArchived}} +
+ {{ctx.Locale.Tr "repo.settings.archive.mirrors_unavailable"}} +
+ {{else}} + {{/* GitHub: the description first, then the mirrors in a box (or an empty state), then the form below. */}} +
+ {{if $newMirrorsEntirelyEnabled}} + {{ctx.Locale.Tr "mirror_settings.docs.summary"}} + {{ctx.Locale.Tr "mirror_settings.docs.doc_link_title"}}

+ {{ctx.Locale.Tr "mirror_settings.docs.pull_mirror_instructions"}} + {{ctx.Locale.Tr "mirror_settings.docs.doc_link_pull_section"}}
+ {{else if $onlyNewPushMirrorsEnabled}} + {{ctx.Locale.Tr "mirror_settings.docs.disabled_pull_mirror.instructions"}} + {{ctx.Locale.Tr "mirror_settings.docs.more_information_if_disabled"}} + {{ctx.Locale.Tr "mirror_settings.docs.doc_link_title"}}
+ {{else if $onlyNewPullMirrorsEnabled}} + {{ctx.Locale.Tr "mirror_settings.docs.disabled_push_mirror.instructions"}} + {{ctx.Locale.Tr "mirror_settings.docs.disabled_push_mirror.pull_mirror_warning"}} + {{ctx.Locale.Tr "mirror_settings.docs.more_information_if_disabled"}} + {{ctx.Locale.Tr "mirror_settings.docs.doc_link_title"}}

+ {{ctx.Locale.Tr "mirror_settings.docs.disabled_push_mirror.info"}} + {{if $existingPushMirror}} + {{ctx.Locale.Tr "mirror_settings.docs.can_still_use"}} + {{end}} + {{else}} + {{ctx.Locale.Tr "mirror_settings.docs.no_new_mirrors"}} {{ctx.Locale.Tr "mirror_settings.docs.can_still_use"}}
+ {{end}} +
+ + {{if .Repository.IsMirror}} + + + + + + + + + + + {{if $modifyBrokenPullMirror}} + {{/* even if a repo is a pull mirror (IsMirror=true), the PullMirror might still be nil if the mirror migration is broken */}} + + + + + + {{else if $isWorkingPullMirror}} + {{$address := MirrorRemoteAddress $.Context .PullMirror}} + + + + + + + + + {{end}}{{/* end if: $modifyBrokenPullMirror / $isWorkingPullMirror */}} +
{{ctx.Locale.Tr "mirror_settings.mirrored_repository"}}{{ctx.Locale.Tr "mirror_settings.direction.header"}}{{ctx.Locale.Tr "mirror_settings.last_update"}}{{ctx.Locale.Tr "repo.mirror_public_key"}}
+
{{ctx.Locale.Tr "mirror_settings.direction.pull"}}: {{ctx.Locale.Tr "error.occurred"}}
+
{{$address.Address}}{{ctx.Locale.Tr "mirror_settings.direction.pull"}}{{DateUtils.FullTime .PullMirror.UpdatedUnix}} +
+ + +
+
+ {{if $isWorkingPullMirror}} + {{$address := MirrorRemoteAddress $.Context .PullMirror}} +
+ {{template "base/disable_form_autofill"}} + +
+ +
+ + +
+
+
+ + +
+
+ + +

{{ctx.Locale.Tr "repo.mirror_address_desc"}}

+
+
+ + {{ctx.Locale.Tr "repo.need_auth"}} + +
+
+ + +
+
+ + +
+

{{ctx.Locale.Tr "repo.mirror_password_help"}}

+
+
+ + {{if .LFSStartServer}} +
+ +
+ + +
+
+
+ + +

{{ctx.Locale.Tr "repo.mirror_lfs_endpoint_desc" "https://github.com/git-lfs/git-lfs/blob/main/docs/api/server-discovery.md#server-discovery"}}

+
+ {{end}} +
+ +
+
+ {{end}} + {{end}}{{/* end if .Repository.IsMirror */}} + + {{if .PushMirrors}} + + + + + + + + + + + + {{range .PushMirrors}} + + + + + + + + {{end}} + +
{{ctx.Locale.Tr "mirror_settings.pushed_repository"}}{{ctx.Locale.Tr "mirror_settings.direction.header"}}{{ctx.Locale.Tr "mirror_settings.last_update"}}{{ctx.Locale.Tr "repo.mirror_public_key"}}
{{.RemoteAddress}}{{ctx.Locale.Tr "mirror_settings.direction.push"}}{{if .LastUpdateUnix}}{{DateUtils.FullTime .LastUpdateUnix}}{{else}}{{ctx.Locale.Tr "never"}}{{end}} {{if .LastError}}
{{ctx.Locale.Tr "error"}}
{{end}}
{{if not (eq (len .GetPublicKey) 0)}}{{ctx.Locale.Tr "mirror_settings.push_mirror.copy_public_key"}}{{else}}{{ctx.Locale.Tr "mirror_settings.push_mirror.none_ssh"}}{{end}} + +
+ + + +
+
+ + + +
+
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "mirror_settings.push_mirror.none")}} + {{end}} + {{if (not .DisableNewPushMirrors)}} +
+ {{template "base/disable_form_autofill"}} + +
+ + +

{{ctx.Locale.Tr "repo.mirror_address_desc"}}

+
+
+ + +

{{ctx.Locale.Tr "repo.settings.push_mirror.branch_filter.description" (AppDocsURL "user/repo-mirror/#branch-filter") "Forgejo"}}

+
+
+ + {{ctx.Locale.Tr "repo.need_auth"}} + +
+
+ + +
+
+ + +
+ {{if .CanUseSSHMirroring}} +
+
+ + + {{ctx.Locale.Tr "repo.mirror_use_ssh.helper"}} +
+
+ {{end}} +
+
+
+
+ + +
+
+
+ + +
+
+ +
+
+ {{end}} + {{end}} +
+ {{end}} + +

+ {{ctx.Locale.Tr "repo.settings.signing_settings"}} +

+
+
+ +
+
+
+
+ + +

{{ctx.Locale.Tr "repo.settings.trust_model.default.desc"}}

+
+
+
+
+ + +

{{ctx.Locale.Tr "repo.settings.trust_model.collaborator.desc"}}

+
+
+
+
+ + +

{{ctx.Locale.Tr "repo.settings.trust_model.committer.desc"}}

+
+
+
+
+ + +

{{ctx.Locale.Tr "repo.settings.trust_model.collaboratorcommitter.desc"}}

+
+
+
+ +
+
+ +
+
+
+ + {{if .IsAdmin}} +

+ {{ctx.Locale.Tr "repo.settings.admin_settings"}} +

+
+
+ +
+
+ + +
+
+ +
+ +
+
+ + {{/* The indexers as GitHub's box rows: what is indexed on the left, the action on the right. */}} +
+ +
+ {{if .CodeIndexerEnabled}} +
+
+
{{ctx.Locale.Tr "repo.settings.admin_code_indexer"}}
+
+ {{ctx.Locale.Tr "repo.settings.admin_indexer_commit_sha"}} + {{if .CodeIndexerStatus}} + {{ShortSha .CodeIndexerStatus.CommitSha}} + {{else}} + {{ctx.Locale.Tr "repo.settings.admin_indexer_unindexed"}} + {{end}} +
+
+
+ +
+
+ {{end}} +
+
+
{{ctx.Locale.Tr "repo.issue_indexer.title"}}
+
+
+ +
+
+
+
+
{{ctx.Locale.Tr "repo.settings.admin_stats_indexer"}}
+
+ {{if and .StatsIndexerStatus .StatsIndexerStatus.CommitSha}} + {{ctx.Locale.Tr "repo.settings.admin_indexer_commit_sha"}} + {{ShortSha .StatsIndexerStatus.CommitSha}} + {{else}} + {{ctx.Locale.Tr "repo.settings.admin_indexer_unindexed"}} + {{end}} +
+
+
+ +
+
+
+
+
+ {{end}} + + {{if .Permission.IsOwner}} +

+ {{ctx.Locale.Tr "repo.settings.danger_zone"}} +

+
+
+ {{if .Repository.IsMirror}} +
+
+
{{ctx.Locale.Tr "repo.settings.convert"}}
+
{{ctx.Locale.Tr "repo.settings.convert_desc"}}
+
+
+ +
+
+ {{end}} + {{if and .Repository.IsFork .Repository.Owner.CanCreateRepo}} +
+
+
{{ctx.Locale.Tr "repo.settings.convert_fork"}}
+
{{ctx.Locale.Tr "repo.settings.convert_fork_desc"}}
+
+
+ +
+
+ {{end}} +
+
+
{{ctx.Locale.Tr "repo.settings.transfer.title"}}
+
+ {{if .RepoTransfer}} + {{ctx.Locale.Tr "repo.settings.transfer_started" .RepoTransfer.Recipient.DisplayName}} + {{else}} + {{ctx.Locale.Tr "repo.settings.transfer_desc"}} + {{end}} +
+
+
+ {{if .RepoTransfer}} +
+ + +
+ {{else}} + + {{end}} +
+
+ {{if .Permission.CanRead $.UnitTypeWiki}} + {{if ne $.Repository.GetWikiBranchName .DefaultWikiBranchName}} +
+
+
{{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main"}}
+
{{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main_desc" .DefaultWikiBranchName}}
+
+
+ +
+
+ {{end}} +
+
+
{{ctx.Locale.Tr "repo.settings.wiki_delete"}}
+
{{ctx.Locale.Tr "repo.settings.wiki_delete_desc"}}
+
+
+ +
+
+ {{end}} +
+
+
{{ctx.Locale.Tr "repo.settings.delete"}}
+
{{ctx.Locale.Tr "repo.settings.delete_desc"}}
+
+
+ +
+
+ {{if not .Repository.IsMirror}} +
+
+ {{if .Repository.IsArchived}} +
{{ctx.Locale.Tr "repo.settings.unarchive.header"}}
+
{{ctx.Locale.Tr "repo.settings.unarchive.text"}}
+ {{else}} +
{{ctx.Locale.Tr "repo.settings.archive.header"}}
+
{{ctx.Locale.Tr "repo.settings.archive.text"}}
+ {{end}} +
+
+ +
+
+ {{end}} +
+
+ {{end}} +
+{{template "repo/settings/layout_footer" .}} + +{{if .Permission.IsOwner}} + {{if .Repository.IsMirror}} + +
+
{{ctx.Locale.Tr "repo.settings.convert"}}
+
+
+ {{ctx.Locale.Tr "repo.settings.convert_notices_1"}} +
+
+
+
+ +
+ +
+
+ + +
+
+
+ + +
+
+
+
+ {{end}} + {{if and .Repository.IsFork .Repository.Owner.CanCreateRepo}} + +
+
{{ctx.Locale.Tr "repo.settings.convert_fork"}}
+
+
+ {{ctx.Locale.Tr "repo.settings.convert_fork_notices_1"}} +
+
+
+
+ +
+ +
+
+ + +
+
+
+ + +
+
+
+
+ {{end}} + +
+
{{ctx.Locale.Tr "repo.settings.transfer.modal.title"}}
+
+
+ {{ctx.Locale.Tr "repo.settings.transfer_notices_1"}}
+ {{ctx.Locale.Tr "repo.settings.transfer_notices_2"}}
+ {{ctx.Locale.Tr "repo.settings.transfer_notices_3"}} +
+
+
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+ + +
+
{{ctx.Locale.Tr "repo.settings.delete"}}
+
+
+ {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}
+ {{ctx.Locale.Tr "repo.settings.delete_notices_2" .Repository.FullName}} + {{if .Repository.NumForks}}
+ {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}} + {{end}} +
+
+
+
+ +
+ +
+
+ + +
+
+
+ + +
+
+
+
+ + {{if .Repository.UnitEnabled $.Context $.UnitTypeWiki}} + +
+
{{ctx.Locale.Tr "repo.settings.wiki_delete"}}
+
+
+ {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}
+ {{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name}} +
+
+
+
+ +
+ +
+
+ + +
+
+
+ + +
+
+
+
+ {{if ne $.Repository.GetWikiBranchName .DefaultWikiBranchName}} + +
+
{{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main"}}
+
+
+
    +
  • {{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main_notices_1"}}
  • +
  • {{ctx.Locale.Tr "repo.settings.wiki_rename_branch_main_notices_2" .Repository.Name}}
  • +
+
+
+
+
+ +
+ +
+
+ + +
+
+
+ + +
+
+
+
+ {{end}} + {{end}} + + {{if not .Repository.IsMirror}} + +
+
+ {{if .Repository.IsArchived}} + {{ctx.Locale.Tr "repo.settings.unarchive.header"}} + {{else}} + {{ctx.Locale.Tr "repo.settings.archive.header"}} + {{end}} +
+
+
+ {{if .Repository.IsArchived}} + {{ctx.Locale.Tr "repo.settings.unarchive.text"}} + {{else}} + {{ctx.Locale.Tr "repo.settings.archive.text"}} + {{end}} +
+
+
+ + +
+ + +
+
+
+
+ {{end}} +{{end}} + +{{template "repo/settings/push_mirror_sync_modal" .}} diff --git a/templates/repo/settings/tags.tmpl b/templates/repo/settings/tags.tmpl new file mode 100644 index 00000000..b3cb9e53 --- /dev/null +++ b/templates/repo/settings/tags.tmpl @@ -0,0 +1,119 @@ +{{/* Forgejo's tag protection without its nested grid and boxes: the list, then the add form. */}} +{{template "repo/settings/layout_head" (dict "ctxData" . "pageClass" "repository settings edit")}} +
+ {{if .Repository.IsArchived}} +
+ {{ctx.Locale.Tr "repo.settings.archive.tagsettings_unavailable"}} +
+ {{else}} +

+ {{ctx.Locale.Tr "tag_protection.header"}} +

+ + {{/* GitHub's order: the protected tags in a box (or an empty state), then the form to add one, flat. */}} +
+ {{if .ProtectedTags}} + + + + + + + + {{range .ProtectedTags}} + + + + + + {{end}} + +
{{ctx.Locale.Tr "tag_protection.pattern.header"}}{{ctx.Locale.Tr "tag_protection.allowed.header"}}
{{.NamePattern}}
+ {{if or .AllowlistUserIDs (and $.Owner.IsOrganization .AllowlistTeamIDs)}} + {{$userIDs := .AllowlistUserIDs}} + {{range $.Users}} + {{if SliceUtils.Contains $userIDs .ID}} + {{ctx.AvatarUtils.Avatar . 26}} {{.GetDisplayName}} + {{end}} + {{end}} + {{if $.Owner.IsOrganization}} + {{$teamIDs := .AllowlistTeamIDs}} + {{range $.Teams}} + {{if SliceUtils.Contains $teamIDs .ID}} + {{.Name}} + {{end}} + {{end}} + {{end}} + {{else}} + {{ctx.Locale.Tr "tag_protection.allowed.noone"}} + {{end}} + + {{ctx.Locale.Tr "edit"}} +
+ + +
+
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "tag_protection.none")}} + {{end}} +
+
+ + +
+
+ + +
+ {{if .Owner.IsOrganization}} +
+ + +
+ {{end}} +
+ {{if .PageIsEditProtectedTag}} + + + {{ctx.Locale.Tr "cancel"}} + + {{else}} + + {{end}} +
+
+
+ {{end}} +
+{{template "repo/settings/layout_footer" .}} diff --git a/templates/repo/settings/webhook/base_list.tmpl b/templates/repo/settings/webhook/base_list.tmpl new file mode 100644 index 00000000..51d28ac1 --- /dev/null +++ b/templates/repo/settings/webhook/base_list.tmpl @@ -0,0 +1,33 @@ +{{/* GitHub's webhooks list: the description, then each hook as a box row with its status, URL and actions. Shared by repository, organization, personal and site administration settings. */}} +

+ {{/* Settings pages pass their page title, which for organizations is just "Settings"; site administration passes + each list's own title. */}} + {{if .PageIsSettingsHooks}}{{ctx.Locale.Tr "repo.settings.hooks"}}{{else}}{{.Title}}{{end}} +
+ +
+

+
+

{{.Description}}

+ {{if .Webhooks}} +
+ {{range .Webhooks}} +
+
+ {{svg "octicon-dot-fill" 16}} +
+
+ {{.URL}} +
+
+ {{svg "octicon-pencil"}} + +
+
+ {{end}} +
+ {{end}} +
diff --git a/templates/shared/actions/runner_list.tmpl b/templates/shared/actions/runner_list.tmpl new file mode 100644 index 00000000..9b634e8f --- /dev/null +++ b/templates/shared/actions/runner_list.tmpl @@ -0,0 +1,143 @@ +{{/* Forgejo's runner list with GitHub's empty state. */}} +
+ +

+ {{ctx.Locale.Tr "actions.runners.runner_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}}) +
+ + + {{ctx.Locale.Tr "actions.runners.new"}} + +
+

+
+
+ {{template "shared/search/combo" dict "Value" .Keyword "Placeholder" (ctx.Locale.Tr "search.runner_kind")}} +
+
+
+ {{if .Runners}} + + + + + + + + + + + + + {{range .Runners}} + + + + + + + + + {{end}} + +
+ {{ctx.Locale.Tr "actions.runners.name"}} + {{SortArrow "alphabetically" "reversealphabetically" .SortType false}} + + {{ctx.Locale.Tr "actions.runners.labels"}} + + {{ctx.Locale.Tr "actions.runners.owner_type"}} + + {{ctx.Locale.Tr "actions.runners.status"}} + {{SortArrow "online" "offline" .SortType false}} + + {{ctx.Locale.Tr "actions.runners.list_runners.edit_column"}} + + {{ctx.Locale.Tr "actions.runners.list_runners.delete_column"}} +
+ +
{{.UUID}}
+
+ {{if gt (len .AgentLabels) 0}} + {{range .AgentLabels}} +
{{.}}
+ {{end}} + {{else}} + — + {{end}} +
+ {{.BelongsToOwnerType.LocaleString ctx.Locale}} + {{if and $.PageIsAdmin .BelongsToOwnerName}} +
+ {{.BelongsToOwnerName}} + {{end}} +
+
+ {{if .IsActive}} +
+
+
+ {{else if .IsIdle}} +
+
+
+ {{else}} +
+
+
+ {{end}} +
+ {{.StatusLocaleName ctx.Locale}} +
+
+
+ {{if .Editable $.RunnerOwnerID $.RunnerRepoID}} + {{svg "octicon-pencil"}} + {{end}} + + {{if .Editable $.RunnerOwnerID $.RunnerRepoID}} + + {{end}} +
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "actions.runners.none")}} + {{end}} +
+ + {{template "base/paginate" .}} + + +
diff --git a/templates/shared/actions/secrets_list.tmpl b/templates/shared/actions/secrets_list.tmpl new file mode 100644 index 00000000..3550d0de --- /dev/null +++ b/templates/shared/actions/secrets_list.tmpl @@ -0,0 +1,130 @@ +{{/* Forgejo's secrets list with GitHub's empty state. */}} +

+ {{ctx.Locale.Tr "secrets.management"}} +
+ +
+

+
+ {{if .Secrets}} +
+ {{range .Secrets}} +
+
+ {{svg "octicon-key" 32}} +
+
+
+ {{.Name}} +
+
+ ****** +
+
+
+ + {{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} + + + +
+
+ {{end}} +
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "secrets.none")}} + {{end}} +
+ +{{/* Add secret dialog */}} + +
+
+
+
+
+ {{ctx.Locale.Tr "secrets.description"}} +
+
+ + +

{{ctx.Locale.Tr "actions.secrets.mutation.name_description"}}

+
+
+ + +

{{ctx.Locale.Tr "actions.secrets.creation.value_description"}}

+
+
+ {{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}} +
+
+
+{{/* Edit secret dialog */}} + +
+
+
+
+
+ {{ctx.Locale.Tr "secrets.description"}} +
+
+ + +

{{ctx.Locale.Tr "actions.secrets.mutation.name_description"}}

+
+
+ + +

{{ctx.Locale.Tr "actions.secrets.mutation.value_description"}}

+
+
+ {{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}} +
+
+
+ + +
+
{{ctx.Locale.Tr "secrets.deletion.description"}}
+
+ + +
+
+
diff --git a/templates/shared/actions/variables_list.tmpl b/templates/shared/actions/variables_list.tmpl new file mode 100644 index 00000000..5e1578e8 --- /dev/null +++ b/templates/shared/actions/variables_list.tmpl @@ -0,0 +1,103 @@ +{{/* Forgejo's variables list with GitHub's empty state. */}} +

+ {{ctx.Locale.Tr "actions.variables.management"}} +
+ +
+

+
+ {{if .Variables}} +
+ {{range .Variables}} +
+
+ {{svg "octicon-pencil" 32}} +
+
+
+ {{.Name}} +
+
+ {{.Data}} +
+
+
+ + {{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} + + + +
+
+ {{end}} +
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "actions.variables.none")}} + {{end}} +
+ +{{/** Edit variable dialog */}} + +
+
+
+
+
+ {{ctx.Locale.Tr "actions.variables.description"}} +
+
+ + +

{{ctx.Locale.Tr "actions.variables.mutation.name_description"}}

+
+
+ + +

{{ctx.Locale.Tr "actions.variables.mutation.value_description"}}

+
+
+ {{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}} +
+
+
+ + +
+
{{ctx.Locale.Tr "actions.variables.deletion.description"}}
+
+ + +
+
+
diff --git a/templates/shared/blocked_users_list.tmpl b/templates/shared/blocked_users_list.tmpl new file mode 100644 index 00000000..fd83d2da --- /dev/null +++ b/templates/shared/blocked_users_list.tmpl @@ -0,0 +1,28 @@ +{{/* Forgejo's blocked users list with GitHub's empty state. */}} +{{if .BlockedUsers}} +
+ {{range .BlockedUsers}} +
+
+ {{ctx.AvatarUtils.Avatar . 48}} +
+
+
+ {{template "shared/user/name" .}} +
+
+ {{ctx.Locale.Tr "settings.blocked_since" (DateUtils.AbsoluteShort .CreatedUnix)}} +
+
+
+
+ + +
+
+
+ {{end}} +
+{{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "settings.blocked_users_none")}} +{{end}} diff --git a/templates/user/settings/authorized_integrations.tmpl b/templates/user/settings/authorized_integrations.tmpl new file mode 100644 index 00000000..bcb3916b --- /dev/null +++ b/templates/user/settings/authorized_integrations.tmpl @@ -0,0 +1,67 @@ +{{/* Forgejo's authorized integrations with GitHub's empty state. */}} +{{template "user/settings/layout_head" (dict "ctxData" . "pageClass" "user settings applications")}} + +
+

+ {{ctx.Locale.Tr "settings.manage_authorized_integrations"}} +
+ +
+

+
+
+
+ {{ctx.Locale.Tr "settings.authorized_integration.desc"}} +
+ {{range .AuthorizedIntegrations}} +
+
+ {{if eq .UI "forgejo-actions-local"}} + + {{svg "gitea-forgejo" 32}} + + {{else}} + + {{svg "octicon-cloud" 32}} + + {{end}} +
+
+ {{.Name}} +
+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasBeenUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

+
+
+
+ + {{svg "octicon-pencil" 16 "tw-mr-1"}} + {{ctx.Locale.Tr "settings.authorized_integration.edit"}} + + +
+
+ {{else}} + {{template "components/common/settings/blankslate" dict "Title" (ctx.Locale.Tr "settings.authorized_integration.none")}} + {{end}} +
+
+
+ + + +{{template "user/settings/layout_footer" .}} diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl new file mode 100644 index 00000000..196bcf64 --- /dev/null +++ b/templates/user/settings/keys_gpg.tmpl @@ -0,0 +1,129 @@ +{{/* GitHub's empty state when no GPG keys are added; Forgejo has no string for it. */}} +

+ {{ctx.Locale.Tr "settings.manage_gpg_keys"}} +
+ +
+

+
+
+
+ +
+ + +
+ {{if .Err_Signature}} +
+

{{ctx.Locale.Tr "settings.gpg_token_required"}}

+
+
+ + + {{ctx.Locale.Tr "keys.verify.token.hint" (printf "?verify_gpg=%s" .KeyID)}} +
+

{{ctx.Locale.Tr "settings.gpg_token_help"}}

+

{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` .TokenToSign .PaddedKeyID}}

+
+
+
+ + +
+ {{end}} + + + +
+
+
+
+

+ {{ctx.Locale.Tr "settings.gpg_desc"}}
+ {{ctx.Locale.Tr "settings.gpg_helper" "https://docs.codeberg.org/security/gpg-key/"}} +

+
+ {{range .GPGKeys}} +
+
+ {{svg "octicon-key" 32}} +
+
+ {{if .Verified}} + {{svg "octicon-verified"}} {{ctx.Locale.Tr "settings.gpg_key_verified"}} + {{end}} + {{if .Emails}} + {{svg "octicon-mail"}} {{ctx.Locale.Tr "settings.gpg_key_matched_identities"}} {{range .Emails}}{{.Email}} {{end}} + {{end}} +
+ {{ctx.Locale.Tr "settings.key_id"}}: {{.PaddedKeyID}} + {{ctx.Locale.Tr "settings.subkeys"}}: {{range .SubsKey}} {{.PaddedKeyID}} {{end}} +
+
+

+ {{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .AddedUnix)}} + - + {{if not .ExpiredUnix.IsZero}}{{ctx.Locale.Tr "settings.valid_until_date" (DateUtils.AbsoluteShort .ExpiredUnix)}}{{else}}{{ctx.Locale.Tr "settings.valid_forever"}}{{end}} +

+
+
+
+ + {{if and (not .Verified) (ne $.VerifyingID .KeyID)}} + {{ctx.Locale.Tr "settings.gpg_key_verify"}} + {{end}} +
+
+ {{if and (not .Verified) (eq $.VerifyingID .KeyID)}} +
+

{{ctx.Locale.Tr "settings.gpg_token_required"}}

+
+ + + +
+ + + {{ctx.Locale.Tr "keys.verify.token.hint" (printf "?verify_gpg=%s" .KeyID)}} +
+

{{ctx.Locale.Tr "settings.gpg_token_help"}}

+

{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` $.TokenToSign .PaddedKeyID}}

+
+
+
+
+ + +
+ + + + {{ctx.Locale.Tr "settings.cancel"}} + +
+
+ {{end}} + {{end}} +
+ {{if not .GPGKeys}} + {{template "components/common/settings/blankslate" dict "Title" "There are no GPG keys associated with your account."}} + {{end}} + +
diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl new file mode 100644 index 00000000..52bea5bb --- /dev/null +++ b/templates/user/settings/keys_ssh.tmpl @@ -0,0 +1,128 @@ +{{/* GitHub's empty state when no SSH keys are added; Forgejo has no string for it. */}} +

+ {{ctx.Locale.Tr "settings.manage_ssh_keys"}} +
+ +
+

+
+
+
+
+ + +
+
+ + +
+ + + +
+
+
+
+

+ {{ctx.Locale.Tr "settings.ssh_desc"}}
+ {{ctx.Locale.Tr "settings.ssh_helper" "https://docs.codeberg.org/security/ssh-key/" "https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/troubleshooting-ssh"}} +

+
+ {{if .DisableSSH}} +
+ {{ctx.Locale.Tr "settings.ssh_signonly"}} +
+ {{end}} + {{range $index, $key := .Keys}} +
+
+ {{svg "octicon-key" 32}} +
+
+ {{if .Verified}} +
{{svg "octicon-verified"}}{{ctx.Locale.Tr "settings.ssh_key_verified"}}
+ {{end}} +
{{.Name}}
+
+ {{.Fingerprint}} +
+
+

{{ctx.Locale.Tr "settings.added_on" (DateUtils.AbsoluteShort .CreatedUnix)}} — {{svg "octicon-info"}} {{if .HasUsed}}{{ctx.Locale.Tr "settings.last_used"}} {{DateUtils.AbsoluteShort .UpdatedUnix}}{{else}}{{ctx.Locale.Tr "settings.no_activity"}}{{end}}

+
+
+
+ + {{if and (not .Verified) (ne $.VerifyingFingerprint .Fingerprint)}} + {{ctx.Locale.Tr "settings.ssh_key_verify"}} + {{end}} +
+
+ {{if and (not .Verified) (eq $.VerifyingFingerprint .Fingerprint)}} +
+

{{ctx.Locale.Tr "settings.ssh_token_required"}}

+
+ + + +
+ + + {{ctx.Locale.Tr "keys.verify.token.hint" (printf "?verify_ssh=%s" (QueryEscape .Fingerprint))}} +
+
+

{{ctx.Locale.Tr "settings.ssh_token_help"}}

+
echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n {{AppDomain}} -f ~/.ssh/id_ed25519 # or the path to the private key if it is different.
+
+

{{ctx.Locale.Tr "settings.ssh_token_help_ssh_agent"}}

+
bash -c "echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n {{AppDomain}} -f <(echo '{{.OmitEmail}}')"
+
+
+ Windows PowerShell +
cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n {{AppDomain}} -f /path_to_PrivateKey_or_RelatedPublicKey"
+
+
+
+ Windows CMD +
<NUL set /p="{{$.TokenToSign}}"| ssh-keygen -Y sign -n {{AppDomain}} -f /path_to_PrivateKey_or_RelatedPublicKey
+
+
+
+
+
+ + +
+ + + + {{ctx.Locale.Tr "settings.cancel"}} + +
+
+ {{end}} + {{end}} +
+ {{if not .Keys}} + {{template "components/common/settings/blankslate" dict "Title" "There are no SSH keys associated with your account."}} + {{end}} + +
diff --git a/templates/user/settings/layout_head.tmpl b/templates/user/settings/layout_head.tmpl new file mode 100644 index 00000000..9a3c1409 --- /dev/null +++ b/templates/user/settings/layout_head.tmpl @@ -0,0 +1,18 @@ +{{template "base/head" .ctxData}} +
+ {{if not .ctxData.HideNavbarLinks}} +
+ {{template "components/common/settings/context" dict "Avatar" (ctx.AvatarUtils.Avatar .ctxData.SignedUser 48) "Title" (.ctxData.SignedUser.DisplayName) "Login" .ctxData.SignedUser.Name "Subtitle" (ctx.Locale.Tr "user.settings") "Link" .ctxData.SignedUser.HomeLink "LinkIcon" "octicon-person" "LinkLabel" (ctx.Locale.Tr "your_profile")}} +
+ {{end}} +
+ {{template "user/settings/navbar" .ctxData}} +
+ {{template "base/alert" .ctxData}} + {{/* block: user-setting-content */}} + +{{if false}}{{/* to make html structure "likely" complete to prevent IDE warnings */}} +
+
+
+{{end}} diff --git a/templates/user/settings/navbar.tmpl b/templates/user/settings/navbar.tmpl new file mode 100644 index 00000000..3a61380f --- /dev/null +++ b/templates/user/settings/navbar.tmpl @@ -0,0 +1,72 @@ +{{/* GitHub's personal settings nav: an icon per page, grouped under Access, Code, planning, and automation, and + Integrations. Forgejo has no strings for the group names. */}} +{{if not .HideNavbarLinks}} + +{{end}} diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl new file mode 100644 index 00000000..663cb4e1 --- /dev/null +++ b/templates/user/settings/profile.tmpl @@ -0,0 +1,151 @@ +{{/* GitHub's public profile: the form on the left, the profile picture with Forgejo's avatar options in a column on the right. */}} +{{template "user/settings/layout_head" (dict "ctxData" . "pageClass" "user settings profile")}} +
+

+ {{ctx.Locale.Tr "settings.public_profile"}} +

+
+
+
+ {{ctx.Locale.Tr "settings.profile_desc"}} + + + + + + + + + + + +
+ +
+ {{ctx.Locale.Tr "settings.privacy"}} + + + + + + + + +
+ + +
+ + +
+
+{{template "user/settings/layout_footer" .}}