From 3ae72cd9e0896401936e94866559ef66a2fd871e Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 2 Mar 2024 20:01:59 +0800 Subject: [PATCH] :recycle: Brand new post list --- pkg/models/posts.go | 4 +- pkg/server/creators_api.go | 6 +- pkg/server/posts_api.go | 8 +-- pkg/server/startup.go | 2 +- pkg/services/posts.go | 22 +++----- pkg/views/bun.lockb | Bin 151011 -> 152457 bytes pkg/views/embed.go | 6 ++ pkg/views/index.html | 2 +- pkg/views/package.json | 2 + pkg/views/public/favicon.svg | 21 +++++++ pkg/views/src/assets/utils.css | 11 ++++ pkg/views/src/components/posts/PostItem.vue | 31 ++++++++++ pkg/views/src/components/posts/PostList.vue | 21 +++++++ pkg/views/src/layouts/master.vue | 33 ++++++++--- pkg/views/src/main.ts | 55 ++++++++++-------- pkg/views/src/router/index.ts | 5 +- pkg/views/src/scripts/request.ts | 10 ++++ pkg/views/src/stores/userinfo.ts | 56 +++++++++++++++++++ pkg/views/src/stores/wellKnown.ts | 14 +++++ pkg/views/src/views/explore.vue | 59 ++++++++++++++++++++ pkg/views/src/views/landing.vue | 3 - pkg/views/tsconfig.app.json | 2 + pkg/views/vite.config.ts | 6 ++ 23 files changed, 314 insertions(+), 65 deletions(-) create mode 100644 pkg/views/embed.go create mode 100755 pkg/views/public/favicon.svg create mode 100644 pkg/views/src/assets/utils.css create mode 100644 pkg/views/src/components/posts/PostItem.vue create mode 100644 pkg/views/src/components/posts/PostList.vue create mode 100644 pkg/views/src/scripts/request.ts create mode 100644 pkg/views/src/stores/userinfo.ts create mode 100644 pkg/views/src/stores/wellKnown.ts create mode 100644 pkg/views/src/views/explore.vue delete mode 100644 pkg/views/src/views/landing.vue diff --git a/pkg/models/posts.go b/pkg/models/posts.go index 12d9a36..cb8eedb 100644 --- a/pkg/models/posts.go +++ b/pkg/models/posts.go @@ -5,10 +5,8 @@ import "time" type Post struct { BaseModel - Alias string `json:"alias" gorm:"uniqueIndex"` - Title string `json:"title"` Content string `json:"content"` - Tags []Tag `json:"tags" gorm:"many2many:post_tags"` + Hashtags []Tag `json:"tags" gorm:"many2many:post_tags"` Categories []Category `json:"categories" gorm:"many2many:post_categories"` Attachments []Attachment `json:"attachments"` LikedAccounts []PostLike `json:"liked_accounts"` diff --git a/pkg/server/creators_api.go b/pkg/server/creators_api.go index 21f53fb..9d72759 100644 --- a/pkg/server/creators_api.go +++ b/pkg/server/creators_api.go @@ -12,13 +12,13 @@ import ( func getOwnPost(c *fiber.Ctx) error { user := c.Locals("principal").(models.Account) - id := c.Params("postId") + id, _ := c.ParamsInt("postId", 0) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) tx := database.C.Where(&models.Post{ - Alias: id, - AuthorID: user.ID, + BaseModel: models.BaseModel{ID: uint(id)}, + AuthorID: user.ID, }) post, err := services.GetPost(tx) diff --git a/pkg/server/posts_api.go b/pkg/server/posts_api.go index 76bc14a..48d9ef6 100644 --- a/pkg/server/posts_api.go +++ b/pkg/server/posts_api.go @@ -13,12 +13,12 @@ import ( ) func getPost(c *fiber.Ctx) error { - id := c.Params("postId") + id, _ := c.ParamsInt("postId", 0) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) tx := database.C.Where(&models.Post{ - Alias: id, + BaseModel: models.BaseModel{ID: uint(id)}, }).Where("published_at <= ? OR published_at IS NULL", time.Now()) post, err := services.GetPost(tx) @@ -162,8 +162,6 @@ func createPost(c *fiber.Ctx) error { post, err := services.NewPost( user, realm, - data.Alias, - data.Title, data.Content, data.Attachments, data.Categories, @@ -207,8 +205,6 @@ func editPost(c *fiber.Ctx) error { post, err := services.EditPost( post, - data.Alias, - data.Title, data.Content, data.PublishedAt, data.Categories, diff --git a/pkg/server/startup.go b/pkg/server/startup.go index 1fdb923..398a432 100644 --- a/pkg/server/startup.go +++ b/pkg/server/startup.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "code.smartsheep.studio/hydrogen/identity/pkg/views" + "code.smartsheep.studio/hydrogen/interactive/pkg/views" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cache" "github.com/gofiber/fiber/v2/middleware/cors" diff --git a/pkg/services/posts.go b/pkg/services/posts.go index c02ce17..84df779 100644 --- a/pkg/services/posts.go +++ b/pkg/services/posts.go @@ -20,7 +20,7 @@ func PreloadRelatedPost(tx *gorm.DB) *gorm.DB { Preload("Author"). Preload("Attachments"). Preload("Categories"). - Preload("Tags"). + Preload("Hashtags"). Preload("RepostTo"). Preload("ReplyTo"). Preload("RepostTo.Author"). @@ -29,8 +29,8 @@ func PreloadRelatedPost(tx *gorm.DB) *gorm.DB { Preload("ReplyTo.Attachments"). Preload("RepostTo.Categories"). Preload("ReplyTo.Categories"). - Preload("RepostTo.Tags"). - Preload("ReplyTo.Tags") + Preload("RepostTo.Hashtags"). + Preload("ReplyTo.Hashtags") } func FilterPostWithCategory(tx *gorm.DB, alias string) *gorm.DB { @@ -161,7 +161,7 @@ WHERE t.id IN ?`, prefix, prefix, prefix, prefix, prefix), postIds).Scan(&reactI func NewPost( user models.Account, realm *models.Realm, - alias, title, content string, + content string, attachments []models.Attachment, categories []models.Category, tags []models.Tag, @@ -202,11 +202,9 @@ func NewPost( } post = models.Post{ - Alias: alias, - Title: title, Content: content, Attachments: attachments, - Tags: tags, + Hashtags: tags, Categories: categories, AuthorID: user.ID, RealmID: realmId, @@ -225,7 +223,7 @@ func NewPost( BaseModel: models.BaseModel{ID: *post.ReplyID}, }).Preload("Author").First(&op).Error; err == nil { if op.Author.ID != user.ID { - postUrl := fmt.Sprintf("https://%s/posts/%s", viper.GetString("domain"), post.Alias) + postUrl := fmt.Sprintf("https://%s/posts/%d", viper.GetString("domain"), post.ID) err := NotifyAccount( op.Author, fmt.Sprintf("%s replied you", user.Name), @@ -252,7 +250,7 @@ func NewPost( }) for _, account := range accounts { - postUrl := fmt.Sprintf("https://%s/posts/%s", viper.GetString("domain"), post.Alias) + postUrl := fmt.Sprintf("https://%s/posts/%d", viper.GetString("domain"), post.ID) err := NotifyAccount( account, fmt.Sprintf("%s just posted a post", user.Name), @@ -270,7 +268,7 @@ func NewPost( func EditPost( post models.Post, - alias, title, content string, + content string, publishedAt *time.Time, categories []models.Category, tags []models.Tag, @@ -294,11 +292,9 @@ func EditPost( publishedAt = lo.ToPtr(time.Now()) } - post.Alias = alias - post.Title = title post.Content = content post.PublishedAt = *publishedAt - post.Tags = tags + post.Hashtags = tags post.Categories = categories post.Attachments = attachments diff --git a/pkg/views/bun.lockb b/pkg/views/bun.lockb index a5a3806856e2e0efac3a1f92d8f7779dd1aa7f08..5a1b84d3e0bb0c6399457bc7dc3a2f0f09233d1d 100755 GIT binary patch delta 23983 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 W{3qj~td1gtZlH0c4+0HWTK+#*+Ff!0 delta 23460 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 - + Goatplaza diff --git a/pkg/views/package.json b/pkg/views/package.json index 69649f9..8a00dc9 100644 --- a/pkg/views/package.json +++ b/pkg/views/package.json @@ -13,9 +13,11 @@ "format": "prettier --write src/" }, "dependencies": { + "@fontsource/roboto": "^5.0.8", "@mdi/font": "^7.4.47", "@unocss/reset": "^0.58.5", "pinia": "^2.1.7", + "universal-cookie": "^7.1.0", "unocss": "^0.58.5", "vue": "^3.4.15", "vue-router": "^4.2.5", diff --git a/pkg/views/public/favicon.svg b/pkg/views/public/favicon.svg new file mode 100755 index 0000000..d42a1a1 --- /dev/null +++ b/pkg/views/public/favicon.svg @@ -0,0 +1,21 @@ + + SmartSheep Logo + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pkg/views/src/assets/utils.css b/pkg/views/src/assets/utils.css new file mode 100644 index 0000000..52b91bd --- /dev/null +++ b/pkg/views/src/assets/utils.css @@ -0,0 +1,11 @@ +html, body, #app, .v-application { + overflow: auto !important; +} + +.no-scrollbar { + scrollbar-width: none; +} + +.no-scrollbar::-webkit-scrollbar { + width: 0; +} diff --git a/pkg/views/src/components/posts/PostItem.vue b/pkg/views/src/components/posts/PostItem.vue new file mode 100644 index 0000000..844105f --- /dev/null +++ b/pkg/views/src/components/posts/PostItem.vue @@ -0,0 +1,31 @@ + + + + + \ No newline at end of file diff --git a/pkg/views/src/components/posts/PostList.vue b/pkg/views/src/components/posts/PostList.vue new file mode 100644 index 0000000..4cb9771 --- /dev/null +++ b/pkg/views/src/components/posts/PostList.vue @@ -0,0 +1,21 @@ + + + diff --git a/pkg/views/src/layouts/master.vue b/pkg/views/src/layouts/master.vue index 9db7e29..a161a8d 100644 --- a/pkg/views/src/layouts/master.vue +++ b/pkg/views/src/layouts/master.vue @@ -1,13 +1,24 @@ - diff --git a/pkg/views/src/main.ts b/pkg/views/src/main.ts index aa2849e..b517f0b 100644 --- a/pkg/views/src/main.ts +++ b/pkg/views/src/main.ts @@ -1,41 +1,50 @@ -import "virtual:uno.css" +import "virtual:uno.css"; -import { createApp } from "vue" -import { createPinia } from "pinia" +import "./assets/utils.css"; -import "vuetify/styles" -import { createVuetify } from "vuetify" -import * as components from "vuetify/components" -import * as directives from "vuetify/directives" +import { createApp } from "vue"; +import { createPinia } from "pinia"; -import "@mdi/font/css/materialdesignicons.min.css" +import "vuetify/styles"; +import { createVuetify } from "vuetify"; +import { md3 } from "vuetify/blueprints"; +import * as components from "vuetify/components"; +import * as directives from "vuetify/directives"; -import index from "./index.vue" -import router from "./router" +import "@mdi/font/css/materialdesignicons.min.css"; +import "@fontsource/roboto/latin.css"; +import "@unocss/reset/tailwind.css"; -const app = createApp(index) +import index from "./index.vue"; +import router from "./router"; + +const app = createApp(index); app.use( createVuetify({ components, directives, + blueprint: md3, theme: { + defaultTheme: "original", themes: { - light: { - primary: "#4a5099", - secondary: "#2196f3", - accent: "#009688", - error: "#f44336", - warning: "#ff9800", - info: "#03a9f4", - success: "#4caf50" + original: { + colors: { + primary: "#4a5099", + secondary: "#2196f3", + accent: "#009688", + error: "#f44336", + warning: "#ff9800", + info: "#03a9f4", + success: "#4caf50" + } } } } }) -) +); -app.use(createPinia()) -app.use(router) +app.use(createPinia()); +app.use(router); -app.mount("#app") +app.mount("#app"); diff --git a/pkg/views/src/router/index.ts b/pkg/views/src/router/index.ts index 6963185..4943d0f 100644 --- a/pkg/views/src/router/index.ts +++ b/pkg/views/src/router/index.ts @@ -1,6 +1,5 @@ import { createRouter, createWebHistory } from "vue-router" import MasterLayout from "@/layouts/master.vue" -import LandingPage from "@/views/landing.vue" const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -11,8 +10,8 @@ const router = createRouter({ children: [ { path: "/", - name: "landing", - component: LandingPage + name: "explore", + component: () => import("@/views/explore.vue") } ] } diff --git a/pkg/views/src/scripts/request.ts b/pkg/views/src/scripts/request.ts new file mode 100644 index 0000000..5540ff2 --- /dev/null +++ b/pkg/views/src/scripts/request.ts @@ -0,0 +1,10 @@ +declare global { + interface Window { + __LAUNCHPAD_TARGET__?: string + } +} + +export async function request(input: string, init?: RequestInit) { + const prefix = window.__LAUNCHPAD_TARGET__ ?? "" + return await fetch(prefix + input, init) +} diff --git a/pkg/views/src/stores/userinfo.ts b/pkg/views/src/stores/userinfo.ts new file mode 100644 index 0000000..2f4f1a8 --- /dev/null +++ b/pkg/views/src/stores/userinfo.ts @@ -0,0 +1,56 @@ +import Cookie from "universal-cookie" +import { defineStore } from "pinia" +import { ref } from "vue" +import { request } from "@/scripts/request" + +export interface Userinfo { + isReady: boolean + isLoggedIn: boolean + displayName: string + data: any +} + +const defaultUserinfo: Userinfo = { + isReady: false, + isLoggedIn: false, + displayName: "Citizen", + data: null +} + +export function getAtk(): string { + return new Cookie().get("identity_auth_key") +} + +export function checkLoggedIn(): boolean { + return new Cookie().get("identity_auth_key") +} + +export const useUserinfo = defineStore("userinfo", () => { + const userinfo = ref(defaultUserinfo) + const isReady = ref(false) + + async function readProfiles() { + if (!checkLoggedIn()) { + isReady.value = true; + } + + const res = await request("/api/users/me", { + headers: { "Authorization": `Bearer ${getAtk()}` } + }); + + if (res.status !== 200) { + return; + } + + const data = await res.json(); + + userinfo.value = { + isReady: true, + isLoggedIn: true, + displayName: data["nick"], + data: data + }; + } + + return { userinfo, isReady, readProfiles } +}) diff --git a/pkg/views/src/stores/wellKnown.ts b/pkg/views/src/stores/wellKnown.ts new file mode 100644 index 0000000..431cf84 --- /dev/null +++ b/pkg/views/src/stores/wellKnown.ts @@ -0,0 +1,14 @@ +import { request } from "@/scripts/request" +import { defineStore } from "pinia" +import { ref } from "vue" + +export const useWellKnown = defineStore("well-known", () => { + const wellKnown = ref({}) + + async function readWellKnown() { + const res = await request("/.well-known") + wellKnown.value = await res.json() + } + + return { wellKnown, readWellKnown } +}) diff --git a/pkg/views/src/views/explore.vue b/pkg/views/src/views/explore.vue new file mode 100644 index 0000000..eeb2ef9 --- /dev/null +++ b/pkg/views/src/views/explore.vue @@ -0,0 +1,59 @@ + + + \ No newline at end of file diff --git a/pkg/views/src/views/landing.vue b/pkg/views/src/views/landing.vue deleted file mode 100644 index a02994a..0000000 --- a/pkg/views/src/views/landing.vue +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/pkg/views/tsconfig.app.json b/pkg/views/tsconfig.app.json index e14c754..292c91d 100644 --- a/pkg/views/tsconfig.app.json +++ b/pkg/views/tsconfig.app.json @@ -4,6 +4,8 @@ "exclude": ["src/**/__tests__/*"], "compilerOptions": { "composite": true, + "allowJs": true, + "checkJs": true, "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "baseUrl": ".", diff --git a/pkg/views/vite.config.ts b/pkg/views/vite.config.ts index 7dbfdfa..ed08b91 100644 --- a/pkg/views/vite.config.ts +++ b/pkg/views/vite.config.ts @@ -12,5 +12,11 @@ export default defineConfig({ alias: { "@": fileURLToPath(new URL("./src", import.meta.url)) } + }, + server: { + proxy: { + "/.well-known": "http://localhost:8445", + "/api": "http://localhost:8445" + } } })