Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2

pages: support MultiAccountUser in templates and params

authored by lewis.moe and committed by tangled.org a59006bb bbd871a7

+180 -77
+10
appview/pages/funcmap.go
··· 28 28 emoji "github.com/yuin/goldmark-emoji" 29 29 "tangled.org/core/appview/filetree" 30 30 "tangled.org/core/appview/models" 31 + "tangled.org/core/appview/oauth" 31 32 "tangled.org/core/appview/pages/markup" 32 33 "tangled.org/core/crypto" 33 34 ) ··· 385 384 return "error" 386 385 } 387 386 return fp 387 + }, 388 + "otherAccounts": func(activeDid string, accounts []oauth.AccountInfo) []oauth.AccountInfo { 389 + result := make([]oauth.AccountInfo, 0, len(accounts)) 390 + for _, acc := range accounts { 391 + if acc.Did != activeDid { 392 + result = append(result, acc) 393 + } 394 + } 395 + return result 388 396 }, 389 397 } 390 398 }
+68 -66
appview/pages/pages.go
··· 226 226 } 227 227 228 228 type LoginParams struct { 229 - ReturnUrl string 230 - ErrorCode string 229 + ReturnUrl string 230 + ErrorCode string 231 + AddAccount bool 232 + LoggedInUser *oauth.MultiAccountUser 231 233 } 232 234 233 235 func (p *Pages) Login(w io.Writer, params LoginParams) error { ··· 249 247 } 250 248 251 249 type TermsOfServiceParams struct { 252 - LoggedInUser *oauth.User 250 + LoggedInUser *oauth.MultiAccountUser 253 251 Content template.HTML 254 252 } 255 253 ··· 277 275 } 278 276 279 277 type PrivacyPolicyParams struct { 280 - LoggedInUser *oauth.User 278 + LoggedInUser *oauth.MultiAccountUser 281 279 Content template.HTML 282 280 } 283 281 ··· 305 303 } 306 304 307 305 type BrandParams struct { 308 - LoggedInUser *oauth.User 306 + LoggedInUser *oauth.MultiAccountUser 309 307 } 310 308 311 309 func (p *Pages) Brand(w io.Writer, params BrandParams) error { ··· 313 311 } 314 312 315 313 type TimelineParams struct { 316 - LoggedInUser *oauth.User 314 + LoggedInUser *oauth.MultiAccountUser 317 315 Timeline []models.TimelineEvent 318 316 Repos []models.Repo 319 317 GfiLabel *models.LabelDefinition ··· 324 322 } 325 323 326 324 type GoodFirstIssuesParams struct { 327 - LoggedInUser *oauth.User 325 + LoggedInUser *oauth.MultiAccountUser 328 326 Issues []models.Issue 329 327 RepoGroups []*models.RepoGroup 330 328 LabelDefs map[string]*models.LabelDefinition ··· 337 335 } 338 336 339 337 type UserProfileSettingsParams struct { 340 - LoggedInUser *oauth.User 338 + LoggedInUser *oauth.MultiAccountUser 341 339 Tabs []map[string]any 342 340 Tab string 343 341 } ··· 347 345 } 348 346 349 347 type NotificationsParams struct { 350 - LoggedInUser *oauth.User 348 + LoggedInUser *oauth.MultiAccountUser 351 349 Notifications []*models.NotificationWithEntity 352 350 UnreadCount int 353 351 Page pagination.Page ··· 375 373 } 376 374 377 375 type UserKeysSettingsParams struct { 378 - LoggedInUser *oauth.User 376 + LoggedInUser *oauth.MultiAccountUser 379 377 PubKeys []models.PublicKey 380 378 Tabs []map[string]any 381 379 Tab string ··· 386 384 } 387 385 388 386 type UserEmailsSettingsParams struct { 389 - LoggedInUser *oauth.User 387 + LoggedInUser *oauth.MultiAccountUser 390 388 Emails []models.Email 391 389 Tabs []map[string]any 392 390 Tab string ··· 397 395 } 398 396 399 397 type UserNotificationSettingsParams struct { 400 - LoggedInUser *oauth.User 398 + LoggedInUser *oauth.MultiAccountUser 401 399 Preferences *models.NotificationPreferences 402 400 Tabs []map[string]any 403 401 Tab string ··· 417 415 } 418 416 419 417 type KnotsParams struct { 420 - LoggedInUser *oauth.User 418 + LoggedInUser *oauth.MultiAccountUser 421 419 Registrations []models.Registration 422 420 Tabs []map[string]any 423 421 Tab string ··· 428 426 } 429 427 430 428 type KnotParams struct { 431 - LoggedInUser *oauth.User 429 + LoggedInUser *oauth.MultiAccountUser 432 430 Registration *models.Registration 433 431 Members []string 434 432 Repos map[string][]models.Repo ··· 450 448 } 451 449 452 450 type SpindlesParams struct { 453 - LoggedInUser *oauth.User 451 + LoggedInUser *oauth.MultiAccountUser 454 452 Spindles []models.Spindle 455 453 Tabs []map[string]any 456 454 Tab string ··· 471 469 } 472 470 473 471 type SpindleDashboardParams struct { 474 - LoggedInUser *oauth.User 472 + LoggedInUser *oauth.MultiAccountUser 475 473 Spindle models.Spindle 476 474 Members []string 477 475 Repos map[string][]models.Repo ··· 484 482 } 485 483 486 484 type NewRepoParams struct { 487 - LoggedInUser *oauth.User 485 + LoggedInUser *oauth.MultiAccountUser 488 486 Knots []string 489 487 } 490 488 ··· 493 491 } 494 492 495 493 type ForkRepoParams struct { 496 - LoggedInUser *oauth.User 494 + LoggedInUser *oauth.MultiAccountUser 497 495 Knots []string 498 496 RepoInfo repoinfo.RepoInfo 499 497 } ··· 531 529 } 532 530 533 531 type ProfileOverviewParams struct { 534 - LoggedInUser *oauth.User 532 + LoggedInUser *oauth.MultiAccountUser 535 533 Repos []models.Repo 536 534 CollaboratingRepos []models.Repo 537 535 ProfileTimeline *models.ProfileTimeline ··· 545 543 } 546 544 547 545 type ProfileReposParams struct { 548 - LoggedInUser *oauth.User 546 + LoggedInUser *oauth.MultiAccountUser 549 547 Repos []models.Repo 550 548 Card *ProfileCard 551 549 Active string ··· 557 555 } 558 556 559 557 type ProfileStarredParams struct { 560 - LoggedInUser *oauth.User 558 + LoggedInUser *oauth.MultiAccountUser 561 559 Repos []models.Repo 562 560 Card *ProfileCard 563 561 Active string ··· 569 567 } 570 568 571 569 type ProfileStringsParams struct { 572 - LoggedInUser *oauth.User 570 + LoggedInUser *oauth.MultiAccountUser 573 571 Strings []models.String 574 572 Card *ProfileCard 575 573 Active string ··· 582 580 583 581 type FollowCard struct { 584 582 UserDid string 585 - LoggedInUser *oauth.User 583 + LoggedInUser *oauth.MultiAccountUser 586 584 FollowStatus models.FollowStatus 587 585 FollowersCount int64 588 586 FollowingCount int64 ··· 590 588 } 591 589 592 590 type ProfileFollowersParams struct { 593 - LoggedInUser *oauth.User 591 + LoggedInUser *oauth.MultiAccountUser 594 592 Followers []FollowCard 595 593 Card *ProfileCard 596 594 Active string ··· 602 600 } 603 601 604 602 type ProfileFollowingParams struct { 605 - LoggedInUser *oauth.User 603 + LoggedInUser *oauth.MultiAccountUser 606 604 Following []FollowCard 607 605 Card *ProfileCard 608 606 Active string ··· 624 622 } 625 623 626 624 type EditBioParams struct { 627 - LoggedInUser *oauth.User 625 + LoggedInUser *oauth.MultiAccountUser 628 626 Profile *models.Profile 629 627 } 630 628 ··· 633 631 } 634 632 635 633 type EditPinsParams struct { 636 - LoggedInUser *oauth.User 634 + LoggedInUser *oauth.MultiAccountUser 637 635 Profile *models.Profile 638 636 AllRepos []PinnedRepo 639 637 } ··· 660 658 } 661 659 662 660 type RepoIndexParams struct { 663 - LoggedInUser *oauth.User 661 + LoggedInUser *oauth.MultiAccountUser 664 662 RepoInfo repoinfo.RepoInfo 665 663 Active string 666 664 TagMap map[string][]string ··· 709 707 } 710 708 711 709 type RepoLogParams struct { 712 - LoggedInUser *oauth.User 710 + LoggedInUser *oauth.MultiAccountUser 713 711 RepoInfo repoinfo.RepoInfo 714 712 TagMap map[string][]string 715 713 Active string ··· 726 724 } 727 725 728 726 type RepoCommitParams struct { 729 - LoggedInUser *oauth.User 727 + LoggedInUser *oauth.MultiAccountUser 730 728 RepoInfo repoinfo.RepoInfo 731 729 Active string 732 730 EmailToDid map[string]string ··· 745 743 } 746 744 747 745 type RepoTreeParams struct { 748 - LoggedInUser *oauth.User 746 + LoggedInUser *oauth.MultiAccountUser 749 747 RepoInfo repoinfo.RepoInfo 750 748 Active string 751 749 BreadCrumbs [][]string ··· 800 798 } 801 799 802 800 type RepoBranchesParams struct { 803 - LoggedInUser *oauth.User 801 + LoggedInUser *oauth.MultiAccountUser 804 802 RepoInfo repoinfo.RepoInfo 805 803 Active string 806 804 types.RepoBranchesResponse ··· 812 810 } 813 811 814 812 type RepoTagsParams struct { 815 - LoggedInUser *oauth.User 813 + LoggedInUser *oauth.MultiAccountUser 816 814 RepoInfo repoinfo.RepoInfo 817 815 Active string 818 816 types.RepoTagsResponse ··· 826 824 } 827 825 828 826 type RepoArtifactParams struct { 829 - LoggedInUser *oauth.User 827 + LoggedInUser *oauth.MultiAccountUser 830 828 RepoInfo repoinfo.RepoInfo 831 829 Artifact models.Artifact 832 830 } ··· 836 834 } 837 835 838 836 type RepoBlobParams struct { 839 - LoggedInUser *oauth.User 837 + LoggedInUser *oauth.MultiAccountUser 840 838 RepoInfo repoinfo.RepoInfo 841 839 Active string 842 840 BreadCrumbs [][]string ··· 860 858 } 861 859 862 860 type RepoSettingsParams struct { 863 - LoggedInUser *oauth.User 861 + LoggedInUser *oauth.MultiAccountUser 864 862 RepoInfo repoinfo.RepoInfo 865 863 Collaborators []Collaborator 866 864 Active string ··· 879 877 } 880 878 881 879 type RepoGeneralSettingsParams struct { 882 - LoggedInUser *oauth.User 880 + LoggedInUser *oauth.MultiAccountUser 883 881 RepoInfo repoinfo.RepoInfo 884 882 Labels []models.LabelDefinition 885 883 DefaultLabels []models.LabelDefinition ··· 897 895 } 898 896 899 897 type RepoAccessSettingsParams struct { 900 - LoggedInUser *oauth.User 898 + LoggedInUser *oauth.MultiAccountUser 901 899 RepoInfo repoinfo.RepoInfo 902 900 Active string 903 901 Tabs []map[string]any ··· 911 909 } 912 910 913 911 type RepoPipelineSettingsParams struct { 914 - LoggedInUser *oauth.User 912 + LoggedInUser *oauth.MultiAccountUser 915 913 RepoInfo repoinfo.RepoInfo 916 914 Active string 917 915 Tabs []map[string]any ··· 927 925 } 928 926 929 927 type RepoIssuesParams struct { 930 - LoggedInUser *oauth.User 928 + LoggedInUser *oauth.MultiAccountUser 931 929 RepoInfo repoinfo.RepoInfo 932 930 Active string 933 931 Issues []models.Issue ··· 944 942 } 945 943 946 944 type RepoSingleIssueParams struct { 947 - LoggedInUser *oauth.User 945 + LoggedInUser *oauth.MultiAccountUser 948 946 RepoInfo repoinfo.RepoInfo 949 947 Active string 950 948 Issue *models.Issue ··· 963 961 } 964 962 965 963 type EditIssueParams struct { 966 - LoggedInUser *oauth.User 964 + LoggedInUser *oauth.MultiAccountUser 967 965 RepoInfo repoinfo.RepoInfo 968 966 Issue *models.Issue 969 967 Action string ··· 987 985 } 988 986 989 987 type RepoNewIssueParams struct { 990 - LoggedInUser *oauth.User 988 + LoggedInUser *oauth.MultiAccountUser 991 989 RepoInfo repoinfo.RepoInfo 992 990 Issue *models.Issue // existing issue if any -- passed when editing 993 991 Active string ··· 1001 999 } 1002 1000 1003 1001 type EditIssueCommentParams struct { 1004 - LoggedInUser *oauth.User 1002 + LoggedInUser *oauth.MultiAccountUser 1005 1003 RepoInfo repoinfo.RepoInfo 1006 1004 Issue *models.Issue 1007 1005 Comment *models.IssueComment ··· 1012 1010 } 1013 1011 1014 1012 type ReplyIssueCommentPlaceholderParams struct { 1015 - LoggedInUser *oauth.User 1013 + LoggedInUser *oauth.MultiAccountUser 1016 1014 RepoInfo repoinfo.RepoInfo 1017 1015 Issue *models.Issue 1018 1016 Comment *models.IssueComment ··· 1023 1021 } 1024 1022 1025 1023 type ReplyIssueCommentParams struct { 1026 - LoggedInUser *oauth.User 1024 + LoggedInUser *oauth.MultiAccountUser 1027 1025 RepoInfo repoinfo.RepoInfo 1028 1026 Issue *models.Issue 1029 1027 Comment *models.IssueComment ··· 1034 1032 } 1035 1033 1036 1034 type IssueCommentBodyParams struct { 1037 - LoggedInUser *oauth.User 1035 + LoggedInUser *oauth.MultiAccountUser 1038 1036 RepoInfo repoinfo.RepoInfo 1039 1037 Issue *models.Issue 1040 1038 Comment *models.IssueComment ··· 1045 1043 } 1046 1044 1047 1045 type RepoNewPullParams struct { 1048 - LoggedInUser *oauth.User 1046 + LoggedInUser *oauth.MultiAccountUser 1049 1047 RepoInfo repoinfo.RepoInfo 1050 1048 Branches []types.Branch 1051 1049 Strategy string ··· 1062 1060 } 1063 1061 1064 1062 type RepoPullsParams struct { 1065 - LoggedInUser *oauth.User 1063 + LoggedInUser *oauth.MultiAccountUser 1066 1064 RepoInfo repoinfo.RepoInfo 1067 1065 Pulls []*models.Pull 1068 1066 Active string ··· 1099 1097 } 1100 1098 1101 1099 type RepoSinglePullParams struct { 1102 - LoggedInUser *oauth.User 1100 + LoggedInUser *oauth.MultiAccountUser 1103 1101 RepoInfo repoinfo.RepoInfo 1104 1102 Active string 1105 1103 Pull *models.Pull ··· 1124 1122 } 1125 1123 1126 1124 type RepoPullPatchParams struct { 1127 - LoggedInUser *oauth.User 1125 + LoggedInUser *oauth.MultiAccountUser 1128 1126 RepoInfo repoinfo.RepoInfo 1129 1127 Pull *models.Pull 1130 1128 Stack models.Stack ··· 1141 1139 } 1142 1140 1143 1141 type RepoPullInterdiffParams struct { 1144 - LoggedInUser *oauth.User 1142 + LoggedInUser *oauth.MultiAccountUser 1145 1143 RepoInfo repoinfo.RepoInfo 1146 1144 Pull *models.Pull 1147 1145 Round int ··· 1194 1192 } 1195 1193 1196 1194 type PullResubmitParams struct { 1197 - LoggedInUser *oauth.User 1195 + LoggedInUser *oauth.MultiAccountUser 1198 1196 RepoInfo repoinfo.RepoInfo 1199 1197 Pull *models.Pull 1200 1198 SubmissionId int ··· 1205 1203 } 1206 1204 1207 1205 type PullActionsParams struct { 1208 - LoggedInUser *oauth.User 1206 + LoggedInUser *oauth.MultiAccountUser 1209 1207 RepoInfo repoinfo.RepoInfo 1210 1208 Pull *models.Pull 1211 1209 RoundNumber int ··· 1220 1218 } 1221 1219 1222 1220 type PullNewCommentParams struct { 1223 - LoggedInUser *oauth.User 1221 + LoggedInUser *oauth.MultiAccountUser 1224 1222 RepoInfo repoinfo.RepoInfo 1225 1223 Pull *models.Pull 1226 1224 RoundNumber int ··· 1231 1229 } 1232 1230 1233 1231 type RepoCompareParams struct { 1234 - LoggedInUser *oauth.User 1232 + LoggedInUser *oauth.MultiAccountUser 1235 1233 RepoInfo repoinfo.RepoInfo 1236 1234 Forks []models.Repo 1237 1235 Branches []types.Branch ··· 1250 1248 } 1251 1249 1252 1250 type RepoCompareNewParams struct { 1253 - LoggedInUser *oauth.User 1251 + LoggedInUser *oauth.MultiAccountUser 1254 1252 RepoInfo repoinfo.RepoInfo 1255 1253 Forks []models.Repo 1256 1254 Branches []types.Branch ··· 1267 1265 } 1268 1266 1269 1267 type RepoCompareAllowPullParams struct { 1270 - LoggedInUser *oauth.User 1268 + LoggedInUser *oauth.MultiAccountUser 1271 1269 RepoInfo repoinfo.RepoInfo 1272 1270 Base string 1273 1271 Head string ··· 1287 1285 } 1288 1286 1289 1287 type LabelPanelParams struct { 1290 - LoggedInUser *oauth.User 1288 + LoggedInUser *oauth.MultiAccountUser 1291 1289 RepoInfo repoinfo.RepoInfo 1292 1290 Defs map[string]*models.LabelDefinition 1293 1291 Subject string ··· 1299 1297 } 1300 1298 1301 1299 type EditLabelPanelParams struct { 1302 - LoggedInUser *oauth.User 1300 + LoggedInUser *oauth.MultiAccountUser 1303 1301 RepoInfo repoinfo.RepoInfo 1304 1302 Defs map[string]*models.LabelDefinition 1305 1303 Subject string ··· 1311 1309 } 1312 1310 1313 1311 type PipelinesParams struct { 1314 - LoggedInUser *oauth.User 1312 + LoggedInUser *oauth.MultiAccountUser 1315 1313 RepoInfo repoinfo.RepoInfo 1316 1314 Pipelines []models.Pipeline 1317 1315 Active string ··· 1354 1352 } 1355 1353 1356 1354 type WorkflowParams struct { 1357 - LoggedInUser *oauth.User 1355 + LoggedInUser *oauth.MultiAccountUser 1358 1356 RepoInfo repoinfo.RepoInfo 1359 1357 Pipeline models.Pipeline 1360 1358 Workflow string ··· 1368 1366 } 1369 1367 1370 1368 type PutStringParams struct { 1371 - LoggedInUser *oauth.User 1369 + LoggedInUser *oauth.MultiAccountUser 1372 1370 Action string 1373 1371 1374 1372 // this is supplied in the case of editing an existing string ··· 1380 1378 } 1381 1379 1382 1380 type StringsDashboardParams struct { 1383 - LoggedInUser *oauth.User 1381 + LoggedInUser *oauth.MultiAccountUser 1384 1382 Card ProfileCard 1385 1383 Strings []models.String 1386 1384 } ··· 1390 1388 } 1391 1389 1392 1390 type StringTimelineParams struct { 1393 - LoggedInUser *oauth.User 1391 + LoggedInUser *oauth.MultiAccountUser 1394 1392 Strings []models.String 1395 1393 } 1396 1394 ··· 1399 1397 } 1400 1398 1401 1399 type SingleStringParams struct { 1402 - LoggedInUser *oauth.User 1400 + LoggedInUser *oauth.MultiAccountUser 1403 1401 ShowRendered bool 1404 1402 RenderToggle bool 1405 1403 RenderedContents template.HTML
+49 -11
appview/pages/templates/layouts/fragments/topbar.html
··· 45 45 {{ define "profileDropdown" }} 46 46 <details class="relative inline-block text-left nav-dropdown"> 47 47 <summary class="cursor-pointer list-none flex items-center gap-1"> 48 - {{ $user := .Did }} 48 + {{ $user := .Active.Did }} 49 49 <img 50 50 src="{{ tinyAvatar $user }}" 51 51 alt="" ··· 53 53 /> 54 54 <span class="hidden md:inline">{{ $user | resolve | truncateAt30 }}</span> 55 55 </summary> 56 - <div class="absolute flex flex-col right-0 mt-4 p-4 rounded w-48 bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700"> 57 - <a href="/{{ $user }}">profile</a> 58 - <a href="/{{ $user }}?tab=repos">repositories</a> 59 - <a href="/{{ $user }}?tab=strings">strings</a> 60 - <a href="/settings">settings</a> 61 - <a href="#" 62 - hx-post="/logout" 63 - hx-swap="none" 64 - class="text-red-400 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"> 65 - logout 56 + <div class="absolute right-0 mt-4 p-4 rounded bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700 shadow-lg z-50" style="width: 14rem;"> 57 + {{ $active := .Active.Did }} 58 + 59 + <div class="pb-2 mb-2 border-b border-gray-200 dark:border-gray-700"> 60 + <div class="flex items-center gap-2"> 61 + <img src="{{ tinyAvatar $active }}" alt="" class="rounded-full h-8 w-8 flex-shrink-0 border border-gray-300 dark:border-gray-700" /> 62 + <div class="flex-1 overflow-hidden"> 63 + <p class="font-medium text-sm truncate">{{ $active | resolve }}</p> 64 + <p class="text-xs text-green-600 dark:text-green-400">active</p> 65 + </div> 66 + </div> 67 + </div> 68 + 69 + {{ $others := .Accounts | otherAccounts $active }} 70 + {{ if $others }} 71 + <div class="pb-2 mb-2 border-b border-gray-200 dark:border-gray-700"> 72 + <p class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wide mb-1">Switch Account</p> 73 + {{ range $others }} 74 + <button 75 + type="button" 76 + hx-post="/account/switch" 77 + hx-vals='{"did": "{{ .Did }}"}' 78 + hx-swap="none" 79 + class="flex items-center gap-2 w-full py-1.5 rounded hover:bg-gray-100 dark:hover:bg-gray-700 text-left" 80 + > 81 + <img src="{{ tinyAvatar .Did }}" alt="" class="rounded-full h-6 w-6 flex-shrink-0 border border-gray-300 dark:border-gray-700" /> 82 + <span class="text-sm truncate flex-1">{{ .Did | resolve }}</span> 83 + </button> 84 + {{ end }} 85 + </div> 86 + {{ end }} 87 + 88 + <a href="/login?mode=add_account" class="flex items-center gap-2 py-1 text-sm"> 89 + {{ i "plus" "w-4 h-4 flex-shrink-0" }} 90 + <span>Add another account</span> 66 91 </a> 92 + 93 + <div class="pt-2 mt-2 border-t border-gray-200 dark:border-gray-700 space-y-1"> 94 + <a href="/{{ $active }}" class="block py-1 text-sm">profile</a> 95 + <a href="/{{ $active }}?tab=repos" class="block py-1 text-sm">repositories</a> 96 + <a href="/{{ $active }}?tab=strings" class="block py-1 text-sm">strings</a> 97 + <a href="/settings" class="block py-1 text-sm">settings</a> 98 + <a href="#" 99 + hx-post="/logout" 100 + hx-swap="none" 101 + class="block py-1 text-sm text-red-400 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"> 102 + logout 103 + </a> 104 + </div> 67 105 </div> 68 106 </details> 69 107
+53
appview/pages/templates/user/login.html
··· 20 20 <h2 class="text-center text-xl italic dark:text-white"> 21 21 tightly-knit social coding. 22 22 </h2> 23 + 24 + {{ if .AddAccount }} 25 + <div class="flex gap-2 my-4 bg-blue-50 dark:bg-blue-900/30 border border-blue-300 dark:border-sky-800 rounded px-3 py-2 text-blue-600 dark:text-blue-300"> 26 + <span class="py-1">{{ i "user-plus" "w-4 h-4" }}</span> 27 + <div> 28 + <h5 class="font-medium">Add another account</h5> 29 + <p class="text-sm">Sign in with a different account to add it to your account list.</p> 30 + </div> 31 + </div> 32 + {{ end }} 33 + 34 + {{ if and .LoggedInUser .LoggedInUser.Accounts }} 35 + {{ $accounts := .LoggedInUser.Accounts }} 36 + {{ if $accounts }} 37 + <div class="my-4 border border-gray-200 dark:border-gray-700 rounded overflow-hidden"> 38 + <div class="px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700"> 39 + <span class="text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wide font-medium">Saved accounts</span> 40 + </div> 41 + <div class="divide-y divide-gray-200 dark:divide-gray-700"> 42 + {{ range $accounts }} 43 + <div class="flex items-center justify-between px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700"> 44 + <button 45 + type="button" 46 + hx-post="/account/switch" 47 + hx-vals='{"did": "{{ .Did }}"}' 48 + hx-swap="none" 49 + class="flex items-center gap-2 flex-1 text-left min-w-0" 50 + > 51 + <img src="{{ tinyAvatar .Did }}" alt="" class="rounded-full h-8 w-8 flex-shrink-0 border border-gray-300 dark:border-gray-700" /> 52 + <div class="flex flex-col min-w-0"> 53 + <span class="text-sm font-medium dark:text-white truncate">{{ .Did | resolve | truncateAt30 }}</span> 54 + <span class="text-xs text-gray-500 dark:text-gray-400">Click to switch</span> 55 + </div> 56 + </button> 57 + <button 58 + type="button" 59 + hx-delete="/account/{{ .Did }}" 60 + hx-swap="none" 61 + class="p-1 text-gray-400 hover:text-red-500 dark:hover:text-red-400 flex-shrink-0" 62 + title="Remove account" 63 + > 64 + {{ i "x" "w-4 h-4" }} 65 + </button> 66 + </div> 67 + {{ end }} 68 + </div> 69 + </div> 70 + {{ end }} 71 + {{ end }} 72 + 23 73 <form 24 74 class="mt-4" 25 75 hx-post="/login" ··· 96 46 </span> 97 47 </div> 98 48 <input type="hidden" name="return_url" value="{{ .ReturnUrl }}"> 49 + <input type="hidden" name="add_account" value="{{ if .AddAccount }}true{{ end }}"> 99 50 100 51 <button 101 52 class="btn w-full my-2 mt-6 text-base " ··· 117 66 You have not authorized the app. 118 67 {{ else if eq .ErrorCode "session" }} 119 68 Server failed to create user session. 69 + {{ else if eq .ErrorCode "max_accounts" }} 70 + You have reached the maximum of 20 linked accounts. Please remove an account before adding a new one. 120 71 {{ else }} 121 72 Internal Server error. 122 73 {{ end }}