Others userinfo

This commit is contained in:
LittleSheep 2024-04-21 17:30:50 +08:00
parent 5bde44647b
commit 447ea936e4
4 changed files with 223 additions and 5 deletions

16
.idea/workspace.xml generated
View File

@ -4,8 +4,11 @@
<option name="autoReloadType" value="ALL" /> <option name="autoReloadType" value="ALL" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":sparkles: OAuth"> <list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":truck: Update well known">
<change beforePath="$PROJECT_DIR$/pkg/server/well_known_api.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/well_known_api.go" afterDir="false" /> <change afterPath="$PROJECT_DIR$/pkg/server/ui/directory.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/pkg/views/users/directory/userinfo.gohtml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/server/ui/index.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/ui/index.go" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -52,7 +55,7 @@
"git-widget-placeholder": "refactor/ux", "git-widget-placeholder": "refactor/ux",
"go.import.settings.migrated": "true", "go.import.settings.migrated": "true",
"go.sdk.automatically.set": "true", "go.sdk.automatically.set": "true",
"last_opened_file_path": "/Users/littlesheep/Documents/Projects/Hydrogen/Passport/pkg/views", "last_opened_file_path": "/Users/littlesheep/Documents/Projects/Hydrogen/Passport/pkg/server/ui",
"node.js.detected.package.eslint": "true", "node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)", "node.js.selected.package.eslint": "(autodetect)",
"nodejs_package_manager_path": "npm", "nodejs_package_manager_path": "npm",
@ -68,11 +71,13 @@
}]]></component> }]]></component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS"> <key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/pkg/views" />
<recent name="$PROJECT_DIR$/pkg/server/ui" /> <recent name="$PROJECT_DIR$/pkg/server/ui" />
<recent name="$PROJECT_DIR$/pkg/views/users" />
<recent name="$PROJECT_DIR$/pkg/views" />
<recent name="$PROJECT_DIR$/pkg" /> <recent name="$PROJECT_DIR$/pkg" />
</key> </key>
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/pkg/views/users/directory" />
<recent name="$PROJECT_DIR$/pkg/views/users" /> <recent name="$PROJECT_DIR$/pkg/views/users" />
<recent name="$PROJECT_DIR$/pkg/utils" /> <recent name="$PROJECT_DIR$/pkg/utils" />
<recent name="$PROJECT_DIR$/pkg/services" /> <recent name="$PROJECT_DIR$/pkg/services" />
@ -131,7 +136,8 @@
<MESSAGE value=":sparkles: User center page" /> <MESSAGE value=":sparkles: User center page" />
<MESSAGE value=":sparkles: Personalize" /> <MESSAGE value=":sparkles: Personalize" />
<MESSAGE value=":sparkles: OAuth" /> <MESSAGE value=":sparkles: OAuth" />
<option name="LAST_COMMIT_MESSAGE" value=":sparkles: OAuth" /> <MESSAGE value=":truck: Update well known" />
<option name="LAST_COMMIT_MESSAGE" value=":truck: Update well known" />
</component> </component>
<component name="VgoProject"> <component name="VgoProject">
<settings-migrated>true</settings-migrated> <settings-migrated>true</settings-migrated>

View File

@ -0,0 +1,48 @@
package ui
import (
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/database"
"git.solsynth.dev/hydrogen/passport/pkg/models"
"github.com/gofiber/fiber/v2"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
"github.com/sujit-baniya/flash"
"html/template"
"time"
)
func otherUserinfoPage(c *fiber.Ctx) error {
name := c.Params("account")
var data models.Account
if err := database.C.
Where(&models.Account{Name: name}).
Preload("Profile").
Preload("PersonalPage").
Preload("Contacts").
First(&data).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
var birthday = "Unknown"
if data.Profile.Birthday != nil {
birthday = data.Profile.Birthday.Format(time.RFC822)
}
doc := parser.
NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock).
Parse([]byte(data.PersonalPage.Content))
renderer := html.NewRenderer(html.RendererOptions{Flags: html.CommonFlags | html.HrefTargetBlank})
return c.Render("views/users/directory/userinfo", fiber.Map{
"info": flash.Get(c)["message"],
"uid": fmt.Sprintf("%08d", data.ID),
"joined_at": data.CreatedAt.Format(time.RFC822),
"birthday_at": birthday,
"personal_page": template.HTML(markdown.Render(doc, renderer)),
"userinfo": data,
}, "views/layouts/user-center")
}

View File

@ -37,6 +37,8 @@ func MapUserInterface(A *fiber.App, authFunc func(c *fiber.Ctx, overrides ...str
pages.Post("/mfa/apply", mfaApplyAction) pages.Post("/mfa/apply", mfaApplyAction)
pages.Post("/authorize", authCheckWare, authorizeAction) pages.Post("/authorize", authCheckWare, authorizeAction)
pages.Get("/@:account", otherUserinfoPage)
pages.Get("/users/me", authCheckWare, selfUserinfoPage) pages.Get("/users/me", authCheckWare, selfUserinfoPage)
pages.Get("/users/me/personalize", authCheckWare, personalizePage) pages.Get("/users/me/personalize", authCheckWare, personalizePage)

View File

@ -0,0 +1,162 @@
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@1.4.6/dist/base.min.css">
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@1.4.6/dist/components.min.css">
<link rel="stylesheet" href="https://unpkg.com/@tailwindcss/typography@0.1.2/dist/typography.min.css">
<link rel="stylesheet" href="https://unpkg.com/tailwindcss@1.4.6/dist/utilities.min.css">
<div class="banner-container">
{{if gt (len .userinfo.Banner) 0}}
<img src="/api/avatar/{{.userinfo.Banner}}" alt="Banner" class="banner">
{{end}}
</div>
<div class="left-part name-card">
{{if gt (len .userinfo.Avatar) 0}}
<img src="/api/avatar/{{.userinfo.Avatar}}" alt="Avatar" class="avatar">
{{else}}
<div class="avatar empty">
<span class="material-symbols-outlined">account_circle</span>
</div>
{{end}}
<div class="name">
<h2 class="username">{{.userinfo.Nick}}</h2>
<h6 class="nickname">@{{.userinfo.Name}}</h6>
</div>
{{if gt (len .userinfo.Description) 0}}
<div class="description">{{.userinfo.Description}}</div>
{{else}}
<div class="description empty">No description yet.</div>
{{end}}
<div class="uid">#{{.uid}}</div>
<div class="metadata">
<div><span class="material-symbols-outlined">calendar_month</span> {{.joined_at}}</div>
<div><span class="material-symbols-outlined">cake</span> {{.birthday_at}}</div>
</div>
<div class="actions">
<md-filled-tonal-button disabled class="action">
Add as friend
<span slot="icon" class="material-symbols-outlined">group_add</span>
</md-filled-tonal-button>
</div>
</div>
<div class="right-part">
<article class="personal-page prose">
{{.personal_page}}
</article>
</div>
<style>
.avatar {
display: block;
width: 64px;
height: 64px;
clip-path: circle();
}
.avatar.empty {
display: flex;
justify-content: center;
align-items: center;
background-color: var(--md-sys-color-secondary);
color: var(--md-sys-color-on-secondary);
}
.banner-container {
grid-column: span 2;
}
.banner {
display: block;
object-fit: cover;
border-radius: 28px;
height: 180px;
width: 100%;
}
.name-card {
display: flex;
flex-direction: column;
gap: 1rem;
}
.name-card .name {
display: flex;
align-items: baseline;
gap: 0.3rem;
}
.name-card .username {
margin: 0;
font-size: 1.5rem;
font-weight: 600;
}
.name-card .nickname {
margin: 0;
font-size: 0.75rem;
font-weight: 500;
}
.name-card .uid {
margin-top: -0.8rem;
font-size: 0.7rem;
font-weight: 400;
font-family: Roboto Mono, monospace;
}
.name-card .description {
margin-top: -1.25rem;
}
.description.empty {
font-style: italic;
}
.name-card .metadata {
font-size: 0.85rem;
font-weight: 500;
display: flex;
flex-direction: column;
}
.metadata > div {
display: flex;
align-items: center;
gap: 0.25rem;
}
.metadata .material-symbols-outlined {
font-size: 1rem;
display: block;
}
.actions {
display: flex;
gap: 0.5rem;
margin: 0 -0.5rem;
}
@media (min-width: 768px) {
.actions {
flex-direction: column;
}
}
.actions .action {
width: fit-content;
}
.actions .material-symbols-outlined {
font-size: 20px;
margin-bottom: 4px;
}
.left-part .prose {
min-width: 0;
max-width: unset;
}
</style>