repo_settings.html
·
267 строк
·
13.3 KB
| 1 | {{define "content"}} |
| 2 | {{$repoBg := imageURL .Repo.BackgroundURL}} |
| 3 | <div class="container"> |
| 4 | {{template "repo_header" .}} |
| 5 | |
| 6 | <!-- General Settings --> |
| 7 | <section class="card mb-4"> |
| 8 | <div class="card-header"> |
| 9 | <span class="font-semibold flex items-center gap-2">{{icon "settings" "size-4"}} {{t .Lang "repo.tab.settings"}}</span> |
| 10 | </div> |
| 11 | <form method="post" action="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/settings" enctype="multipart/form-data" class="card-body flex flex-col gap-3"> |
| 12 | <input type="hidden" name="_csrf" value="{{.CSRFToken}}"> |
| 13 | <input type="hidden" id="repo-avatar-data-input" name="avatar_data" value=""> |
| 14 | <input type="hidden" id="remove-repo-avatar-input" name="remove_avatar" value="false"> |
| 15 | <input type="hidden" id="repo-background-data-input" name="background_data" value=""> |
| 16 | <input type="hidden" id="remove-repo-background-input" name="remove_background" value="false"> |
| 17 | |
| 18 | <div class="flex items-center gap-4 flex-wrap pb-3" style="border-bottom:1px solid hsl(var(--border));"> |
| 19 | <div id="repo-avatar-preview-wrap"> |
| 20 | {{avatar .Repo.OwnerUsername (or .Repo.AvatarURL .Repo.OwnerAvatarURL) "avatar-xl"}} |
| 21 | </div> |
| 22 | <div class="flex flex-col gap-1.5"> |
| 23 | <div class="text-sm font-medium">{{t .Lang "repo.avatar"}}</div> |
| 24 | <div class="flex items-center gap-2 flex-wrap"> |
| 25 | <label class="btn btn-outline btn-sm" style="cursor:pointer;"> |
| 26 | {{icon "image" "size-3.5"}} |
| 27 | <span>{{t .Lang "repo.avatar_upload"}}</span> |
| 28 | <input id="repo-avatar-file-input" name="avatar_file" type="file" accept="image/png,image/jpeg,image/webp,image/gif" style="display:none;"> |
| 29 | </label> |
| 30 | {{if .Repo.AvatarURL}} |
| 31 | <button type="button" id="remove-repo-avatar-btn" class="btn btn-ghost btn-sm text-destructive"> |
| 32 | {{icon "trash" "size-3.5"}} |
| 33 | <span>{{t .Lang "repo.avatar_remove"}}</span> |
| 34 | </button> |
| 35 | {{end}} |
| 36 | </div> |
| 37 | <div class="field-hint" style="margin:0;">{{t .Lang "repo.avatar_hint"}}</div> |
| 38 | </div> |
| 39 | </div> |
| 40 | |
| 41 | <div class="flex flex-col gap-2 pb-3" style="border-bottom:1px solid hsl(var(--border));"> |
| 42 | <div class="flex items-center justify-between gap-2 flex-wrap"> |
| 43 | <div> |
| 44 | <div class="text-sm font-medium">{{t .Lang "repo.background"}}</div> |
| 45 | <div class="field-hint" style="margin:0;">{{t .Lang "repo.background_hint"}}</div> |
| 46 | </div> |
| 47 | <div class="flex items-center gap-2 flex-wrap"> |
| 48 | <label class="btn btn-outline btn-sm" style="cursor:pointer;"> |
| 49 | {{icon "image" "size-3.5"}} |
| 50 | <span>{{t .Lang "repo.background_upload"}}</span> |
| 51 | <input id="repo-background-file-input" name="background_file" type="file" accept="image/png,image/jpeg,image/webp,image/gif" style="display:none;"> |
| 52 | </label> |
| 53 | {{if $repoBg}} |
| 54 | <button type="button" id="remove-repo-background-btn" class="btn btn-ghost btn-sm text-destructive"> |
| 55 | {{icon "trash" "size-3.5"}} |
| 56 | <span>{{t .Lang "repo.background_remove"}}</span> |
| 57 | </button> |
| 58 | {{end}} |
| 59 | </div> |
| 60 | </div> |
| 61 | <div id="repo-background-preview" class="background-preview{{if not $repoBg}} is-empty{{end}}"> |
| 62 | {{if $repoBg}} |
| 63 | <img src="{{$repoBg}}" alt=""> |
| 64 | {{else}} |
| 65 | <span class="background-preview-placeholder">{{icon "image" "size-5"}}</span> |
| 66 | {{end}} |
| 67 | </div> |
| 68 | </div> |
| 69 | |
| 70 | <div> |
| 71 | <label class="label" for="description">{{t .Lang "repo.description"}}</label> |
| 72 | <input id="description" name="description" type="text" class="input" value="{{.Repo.Description}}" maxlength="500" placeholder="{{t .Lang "repo.description_ph"}}"> |
| 73 | </div> |
| 74 | |
| 75 | <div class="grid-2"> |
| 76 | <div> |
| 77 | <label class="label" for="default_branch">{{t .Lang "repo.default_branch"}}</label> |
| 78 | <select id="default_branch" name="default_branch" class="select font-mono"> |
| 79 | {{if .Branches}} |
| 80 | {{range .Branches}} |
| 81 | <option value="{{.}}" {{if eq . $.Repo.DefaultBranch}}selected{{end}}>{{.}}</option> |
| 82 | {{end}} |
| 83 | {{else}} |
| 84 | <option value="{{.Repo.DefaultBranch}}" selected>{{.Repo.DefaultBranch}}</option> |
| 85 | {{end}} |
| 86 | </select> |
| 87 | </div> |
| 88 | |
| 89 | <div> |
| 90 | <label class="label" for="visibility">{{t .Lang "repo.visibility"}}</label> |
| 91 | <select id="visibility" name="visibility" class="select"> |
| 92 | <option value="public" {{if not .Repo.IsPrivate}}selected{{end}}>{{t .Lang "repo.public"}}</option> |
| 93 | <option value="private" {{if .Repo.IsPrivate}}selected{{end}}>{{t .Lang "repo.private"}}</option> |
| 94 | </select> |
| 95 | </div> |
| 96 | </div> |
| 97 | |
| 98 | <!-- Feature Toggles for Repository --> |
| 99 | <div class="card p-3 mt-1" style="background:hsl(var(--muted));"> |
| 100 | <div class="font-semibold text-xs text-muted mb-2 uppercase" style="letter-spacing:0.04em;">{{t .Lang "repo.features"}}</div> |
| 101 | <div class="flex flex-col gap-2.5"> |
| 102 | <label class="flex items-center justify-between cursor-pointer"> |
| 103 | <span class="flex items-center gap-2 text-sm font-medium"> |
| 104 | {{icon "issue" "size-4"}} |
| 105 | <span>{{t .Lang "repo.tab.issues"}}</span> |
| 106 | </span> |
| 107 | <input type="checkbox" name="enable_issues" value="true" class="switch" {{if .Repo.EnableIssues}}checked{{end}}> |
| 108 | </label> |
| 109 | <label class="flex items-center justify-between cursor-pointer"> |
| 110 | <span class="flex items-center gap-2 text-sm font-medium"> |
| 111 | {{icon "git-pull-request" "size-4"}} |
| 112 | <span>{{t .Lang "repo.tab.pulls"}}</span> |
| 113 | </span> |
| 114 | <input type="checkbox" name="enable_pulls" value="true" class="switch" {{if .Repo.EnablePulls}}checked{{end}}> |
| 115 | </label> |
| 116 | <label class="flex items-center justify-between cursor-pointer"> |
| 117 | <span class="flex items-center gap-2 text-sm font-medium"> |
| 118 | {{icon "tag" "size-4"}} |
| 119 | <span>{{t .Lang "repo.tab.releases"}}</span> |
| 120 | </span> |
| 121 | <input type="checkbox" name="enable_releases" value="true" class="switch" {{if .Repo.EnableReleases}}checked{{end}}> |
| 122 | </label> |
| 123 | <label class="flex items-center justify-between cursor-pointer"> |
| 124 | <span class="flex items-center gap-2 text-sm font-medium"> |
| 125 | {{icon "activity" "size-4"}} |
| 126 | <span>{{t .Lang "repo.tab.activity"}}</span> |
| 127 | </span> |
| 128 | <input type="checkbox" name="enable_activity" value="true" class="switch" {{if .Repo.EnableActivity}}checked{{end}}> |
| 129 | </label> |
| 130 | </div> |
| 131 | </div> |
| 132 | |
| 133 | <div class="flex items-center justify-end"> |
| 134 | <button type="submit" class="btn btn-primary btn-sm">{{t .Lang "repo.save"}}</button> |
| 135 | </div> |
| 136 | </form> |
| 137 | </section> |
| 138 | |
| 139 | <!-- Collaborators --> |
| 140 | <section class="card mb-4" id="collaborators"> |
| 141 | <div class="card-header"> |
| 142 | <span class="font-semibold flex items-center gap-2">{{icon "users" "size-4"}} {{t .Lang "collab.title"}}</span> |
| 143 | <span class="text-xs text-muted">{{t .Lang "collab.desc"}}</span> |
| 144 | </div> |
| 145 | |
| 146 | <div class="dense-list" style="border-bottom:1px solid hsl(var(--border));"> |
| 147 | <div class="dense-row" style="min-height:2.6rem;padding:0.45rem 0.85rem;"> |
| 148 | <div class="flex items-center gap-2.5 min-w-0"> |
| 149 | {{avatar .Repo.OwnerUsername .Repo.OwnerAvatarURL}} |
| 150 | <div class="min-w-0"> |
| 151 | <a href="/{{.Repo.OwnerUsername}}" class="font-semibold text-sm">{{.Repo.OwnerUsername}}</a> |
| 152 | </div> |
| 153 | </div> |
| 154 | <span class="badge badge-outline">{{t .Lang "collab.owner"}}</span> |
| 155 | </div> |
| 156 | {{range .Collaborators}} |
| 157 | <div class="dense-row" style="min-height:2.6rem;padding:0.45rem 0.85rem;"> |
| 158 | <div class="flex items-center gap-2.5 min-w-0"> |
| 159 | {{avatar .Username .AvatarURL}} |
| 160 | <div class="min-w-0"> |
| 161 | <a href="/{{.Username}}" class="font-semibold text-sm">{{.Username}}</a> |
| 162 | {{if .FullName}}<div class="text-xs text-muted truncate">{{.FullName}}</div>{{end}} |
| 163 | </div> |
| 164 | </div> |
| 165 | <div class="flex items-center gap-2"> |
| 166 | <span class="badge badge-outline font-mono">{{if eq .Role "read"}}{{t $.Lang "collab.role_read"}}{{else}}{{t $.Lang "collab.role_write"}}{{end}}</span> |
| 167 | {{if $.CanManageCollab}} |
| 168 | <form method="post" action="/{{$.Repo.OwnerUsername}}/{{$.Repo.Name}}/settings/collaborators/remove" style="margin:0;"> |
| 169 | <input type="hidden" name="_csrf" value="{{$.CSRFToken}}"> |
| 170 | <input type="hidden" name="user_id" value="{{.UserID}}"> |
| 171 | <button type="submit" class="btn btn-ghost btn-icon" style="width:1.75rem;height:1.75rem;" title="{{t $.Lang "collab.remove"}}"> |
| 172 | {{icon "close" "size-3.5"}} |
| 173 | </button> |
| 174 | </form> |
| 175 | {{end}} |
| 176 | </div> |
| 177 | </div> |
| 178 | {{else}} |
| 179 | <div class="card-body text-xs text-muted">{{t .Lang "collab.empty"}}</div> |
| 180 | {{end}} |
| 181 | </div> |
| 182 | |
| 183 | {{if .CanManageCollab}} |
| 184 | <form method="post" action="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/settings/collaborators/add" class="card-body flex items-end gap-2 flex-wrap"> |
| 185 | <input type="hidden" name="_csrf" value="{{.CSRFToken}}"> |
| 186 | <div style="flex:1 1 12rem;"> |
| 187 | <label class="label" for="collab_username">{{t .Lang "collab.username"}}</label> |
| 188 | <input id="collab_username" name="username" type="text" class="input font-mono" placeholder="{{t .Lang "collab.username_ph"}}" required> |
| 189 | </div> |
| 190 | <div> |
| 191 | <label class="label" for="collab_role">{{t .Lang "collab.role"}}</label> |
| 192 | <select id="collab_role" name="role" class="select"> |
| 193 | <option value="write">{{t .Lang "collab.role_write"}}</option> |
| 194 | <option value="read">{{t .Lang "collab.role_read"}}</option> |
| 195 | </select> |
| 196 | </div> |
| 197 | <button type="submit" class="btn btn-primary btn-sm"> |
| 198 | {{icon "plus" "size-3.5"}} |
| 199 | <span>{{t .Lang "collab.add"}}</span> |
| 200 | </button> |
| 201 | </form> |
| 202 | {{end}} |
| 203 | </section> |
| 204 | |
| 205 | <!-- Rename Repository --> <section class="card mb-4"> |
| 206 | <div class="card-header"> |
| 207 | <span class="font-semibold flex items-center gap-2">{{icon "edit" "size-4"}} {{t .Lang "repo.rename"}}</span> |
| 208 | </div> |
| 209 | <form method="post" action="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/settings/rename" class="card-body flex items-center gap-2"> |
| 210 | <input type="hidden" name="_csrf" value="{{.CSRFToken}}"> |
| 211 | <input name="new_name" type="text" class="input font-mono" value="{{.Repo.Name}}" required pattern="^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$"> |
| 212 | <button type="submit" class="btn btn-outline">{{t .Lang "repo.rename"}}</button> |
| 213 | </form> |
| 214 | </section> |
| 215 | |
| 216 | <!-- Danger Zone --> |
| 217 | <section class="card" style="border-color:hsl(var(--destructive) / 0.45);"> |
| 218 | <div class="card-header" style="border-bottom-color:hsl(var(--destructive) / 0.2);"> |
| 219 | <span class="font-semibold text-destructive flex items-center gap-2">{{icon "alert-circle" "size-4"}} {{t .Lang "repo.danger_zone"}}</span> |
| 220 | </div> |
| 221 | <div class="card-body flex items-center justify-between flex-wrap gap-3"> |
| 222 | <div> |
| 223 | <div class="font-medium text-sm">{{t .Lang "repo.delete"}}</div> |
| 224 | <div class="text-xs text-muted">{{t .Lang "repo.delete_desc"}}</div> |
| 225 | </div> |
| 226 | <button type="button" class="btn btn-destructive btn-sm" data-dialog-open="delete-repo-dialog"> |
| 227 | {{icon "trash" "size-3.5"}} |
| 228 | <span>{{t .Lang "repo.delete"}}</span> |
| 229 | </button> |
| 230 | </div> |
| 231 | </section> |
| 232 | </div> |
| 233 | |
| 234 | <!-- Delete Confirmation Modal --> |
| 235 | <div id="delete-repo-dialog" class="backdrop" role="dialog" aria-modal="true" aria-label="{{t .Lang "repo.delete"}}" aria-hidden="true"> |
| 236 | <div class="dialog-box"> |
| 237 | <div class="card-header"> |
| 238 | <span class="font-semibold text-destructive flex items-center gap-2">{{icon "trash" "size-4"}} {{t .Lang "repo.delete"}}</span> |
| 239 | <button type="button" class="btn btn-ghost btn-icon" data-dialog-close aria-label="{{t .Lang "common.close"}}">{{icon "close" "size-4"}}</button> |
| 240 | </div> |
| 241 | <form method="post" action="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/settings/delete"> |
| 242 | <input type="hidden" name="_csrf" value="{{.CSRFToken}}"> |
| 243 | <div class="card-body flex flex-col gap-3"> |
| 244 | <p class="text-sm text-muted" style="margin:0;"> |
| 245 | {{t .Lang "repo.delete_confirm"}}: <strong class="font-mono" style="color:hsl(var(--foreground));">{{.Repo.Name}}</strong> |
| 246 | </p> |
| 247 | <input |
| 248 | type="text" |
| 249 | name="confirm_name" |
| 250 | class="input font-mono" |
| 251 | placeholder="{{.Repo.Name}}" |
| 252 | autocomplete="off" |
| 253 | required |
| 254 | data-confirm-input="{{.Repo.Name}}" |
| 255 | data-confirm-button="confirm-delete-btn"> |
| 256 | </div> |
| 257 | <div class="card-footer flex items-center justify-end gap-2"> |
| 258 | <button type="button" class="btn btn-outline btn-sm" data-dialog-close>{{t .Lang "common.cancel"}}</button> |
| 259 | <button id="confirm-delete-btn" type="submit" class="btn btn-destructive btn-sm" disabled> |
| 260 | {{icon "trash" "size-3.5"}} |
| 261 | <span>{{t .Lang "repo.delete"}}</span> |
| 262 | </button> |
| 263 | </div> |
| 264 | </form> |
| 265 | </div> |
| 266 | </div> |
| 267 | {{end}} |