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"}} +
+ {{ctx.Locale.Tr "packages.owner.settings.cleanuprules.add"}} +
+

+
+
+ {{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" .}}