Skip to content

Commit d7d7d34

Browse files
committed
Add postsPluginId and improve Polls functionality
This commit adds postsPluginId to the Astro.props in the Votes component and improves the functionality of Polls by adding more detailed attributes to the data. The commit also adds new dependencies to the project, including "@boringer-avatars/vue3", "remark", and "strip-markdown", for better handling of Markdown content and rendering user avatars. A new Vue component, Profile.vue, is also introduced for profile handling.
1 parent 7dbb911 commit d7d7d34

File tree

8 files changed

+212
-31
lines changed

8 files changed

+212
-31
lines changed

.preview/config.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,21 @@ export default () =>
5151
key: 'feeds',
5252
value: [
5353
{
54-
id: 'default-2',
54+
id: 'default-2-id',
55+
title: 'default-2-title',
56+
slugs: 'default-2-slug',
57+
database: {
58+
type: 'documents:redis',
59+
key: uuidv5(
60+
toUtf8Bytes('default-2'),
61+
uuidv5('EXAMPLE_NAMESPACE', uuidv5.URL),
62+
), // > posts::694666bb-b2ec-542b-a5d6-65b470e5c494
63+
},
64+
},
65+
{
66+
id: 'default-3',
67+
title: '',
68+
slugs: 'default-3-slug',
5569
database: {
5670
type: 'documents:redis',
5771
key: uuidv5(

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@
3434
"author": "",
3535
"license": "MPL-2.0",
3636
"dependencies": {
37+
"@boringer-avatars/vue3": "^0.2.1",
3738
"@devprotocol/dev-kit": "8.6.0",
3839
"@devprotocol/util-ts": "4.0.0",
3940
"bignumber.js": "9.1.2",
4041
"ethers": "6.11.1",
4142
"ramda": "0.29.1",
43+
"remark": "^15.0.1",
4244
"sass": "1.75.0",
45+
"strip-markdown": "^6.0.0",
4346
"uuid": "^9.0.1"
4447
},
4548
"resolutions": {

src/Pages/Votes.astro

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ interface Props extends ClubsPropsPages {
1010
adminRolePoints: number
1111
rpcUrl: string
1212
feeds: OptionsDatabase[]
13+
postsPluginId: string
1314
}
1415
15-
const { options, feeds } = Astro.props
16+
const { options, feeds, postsPluginId } = Astro.props
1617
---
1718

18-
<Votes client:load options={options} feeds={feeds} />
19+
<Votes client:load options={options} feeds={feeds} postsPluginId={postsPluginId} />

src/assets/images/icon-lock.png

7.27 KB
Loading

src/components/Pages/Votes.vue

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,123 @@
11
<script lang="ts" setup>
22
import type { Option } from '../../types.ts'
3-
import type { OptionsDatabase } from '@devprotocol/clubs-plugin-posts'
4-
import { decode } from '@devprotocol/clubs-core'
3+
import type { OptionsDatabase, Posts } from '@devprotocol/clubs-plugin-posts'
4+
import {type ClubsProfile, decode} from '@devprotocol/clubs-core'
55
import { onMounted, ref } from 'vue'
6+
import Profile from '../Votes/Profile.vue';
7+
import IconLock from '../../assets/images/icon-lock.png';
8+
import {remark} from 'remark';
9+
import strip from 'strip-markdown'
610
711
type Props = {
812
options: Option[]
913
feeds: OptionsDatabase[]
14+
postsPluginId: string
1015
}
1116
const props = defineProps<Props>()
1217
13-
const polls = ref([])
14-
const error = ref('')
15-
const isLoading = ref(true)
18+
const polls = ref<any[]>([])
1619
17-
const fetchPolls = async () => {
18-
// これでPollのFeedをとってくる
19-
// http://localhost:4321/api/devprotocol:clubs:plugin:posts/default-2/search/has:option/%23poll
20+
const { postsPluginId, feeds } = props
21+
22+
type Polls = {
23+
title: string
24+
values: PostsPlus[]
25+
}
26+
27+
type PostsPlus = Posts & {
28+
image: string
29+
profile: Promise<{
30+
readonly profile: ClubsProfile | undefined;
31+
readonly error: Error | undefined;
32+
}>
33+
stripedMarkdown: string
34+
}
35+
36+
const feedId = ref('')
37+
38+
const fetchPolls = async (feed: OptionsDatabase): Promise<Polls> => {
39+
feedId.value = feed.id
40+
const title = feed.title
2041
2142
const url = new URL(
22-
`/api/devprotocol:clubs:plugin:posts/default-2/search/has:option/%23poll`,
43+
`/api/${postsPluginId}/${feedId.value}/search/has:option/%23poll`,
2344
window.location.origin,
2445
)
2546
26-
fetch(url.toString())
27-
.then(async (res) => {
28-
console.log('res', res.status)
29-
if (res.status === 200) {
30-
const json = await res.json()
31-
polls.value = decode(json.contents)
32-
}
33-
})
34-
.catch((err) => {
35-
console.error(err)
36-
error.value =
37-
'Sorry, but there was an error loading the timeline. Please try again later.'
38-
})
39-
.finally(() => {
40-
isLoading.value = false
41-
})
47+
const res = await fetch(url.toString())
48+
const json = await res.json()
49+
50+
return {
51+
title: title ? title : feedId.value,
52+
values: decode(json.contents)
53+
}
4254
}
4355
4456
onMounted(async () => {
45-
await fetchPolls()
46-
console.log('mounted', polls.value)
57+
await Promise.all(feeds.map(async (feed) => {
58+
const data = await fetchPolls(feed)
59+
60+
data.values = data.values.map((post) => {
61+
post.updated_at = new Date(post.updated_at).toLocaleString('ja-JP')
62+
63+
const images = post.options.find((item) => item.key === '#images')
64+
if (images && images.value.length > 0) {
65+
post.image = images.value[0]
66+
}
67+
68+
remark()
69+
.use(strip)
70+
.process(post.content).then((text) => {
71+
post.stripedMarkdown = text.toString()
72+
})
73+
74+
return post
75+
})
76+
77+
polls.value = [...polls.value, data]
78+
}))
4779
})
4880
</script>
4981

5082
<template>
51-
<h1>Votes2</h1>
83+
<div class="p-4">
84+
<div v-for="poll in polls" :key="poll.title">
85+
<h2 class="mb-4 text-xl">{{ poll.title }}</h2>
86+
<a
87+
v-for="post in poll.values"
88+
:key="post.id"
89+
:href="`/posts/${feedId}/${post.id}`"
90+
class="block mb-4 p-2 bg-gray-100 rounded"
91+
>
92+
<div class="flex justify-between gap-2">
93+
<div class="w-full">
94+
<p class="text-lg font-bold">Post_title: {{ post.title }}</p>
95+
<p class="mb-1 text-xs text-gray-400">{{ post.updated_at }}</p>
96+
<div class="flex justify-between gap-2">
97+
<Profile :address="post.created_by" />
98+
<p v-if="true" class="flex-grow flex-wrap text-lg truncate">
99+
{{ post.stripedMarkdown }}
100+
</p>
101+
<div v-else class="flex flex-col justify-center items-center flex-grow p-2 bg-gray-200 rounded">
102+
<img
103+
class="mb-1 w-5"
104+
:src="IconLock.src"
105+
alt="paper-airplane"
106+
/>
107+
<p class="leading-none">Locked</p>
108+
</div>
109+
</div>
110+
</div>
111+
<figure v-if="!isMasked && post.image">
112+
<img :src="post.image" class="rounded max-w-20 max-h-20 object-cover object-center" alt="post image" />
113+
</figure>
114+
</div>
115+
</a>
116+
<div v-if="poll.length < 1" class="mb-4 p-2 bg-gray-100 rounded">
117+
<p class="w-full text-gray-400 text-center">
118+
Empty :)
119+
</p>
120+
</div>
121+
</div>
122+
</div>
52123
</template>

src/components/Votes/Profile.vue

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<script setup lang="ts">
2+
import { onMounted, ref } from 'vue'
3+
import { ZeroAddress } from 'ethers'
4+
import { Avatar } from '@boringer-avatars/vue3'
5+
import {fetchProfile} from '@devprotocol/clubs-core';
6+
7+
type Props = {
8+
address: string
9+
}
10+
11+
const props = defineProps<Props>()
12+
13+
const avatar = ref('')
14+
const name = ref('')
15+
16+
onMounted(() => {
17+
if (!props.address || props.address === ZeroAddress) {
18+
name.value = truncateEthAddress(props.address)
19+
return
20+
}
21+
22+
// fetch profile
23+
getProfile(props.address)
24+
})
25+
26+
const truncateEthAddress = (address: string) => {
27+
const match = address.match(
28+
/^(0x[a-zA-Z0-9]{4})[a-zA-Z0-9]+([a-zA-Z0-9]{4})$/,
29+
)
30+
if (!match) return address
31+
return `${match[1]}\u2026${match[2]}`
32+
}
33+
34+
const getProfile = async (address: string) => {
35+
const res = await fetchProfile(address)
36+
if (res?.error) {
37+
console.error(res.error)
38+
return
39+
}
40+
41+
avatar.value = res?.profile?.avatar || ''
42+
name.value = res?.profile?.username ?? truncateEthAddress(address)
43+
}
44+
</script>
45+
46+
<template>
47+
<div class="">
48+
<template v-if="avatar">
49+
<div
50+
class="h-8 w-8 rounded-full bg-cover bg-center bg-no-repeat"
51+
:style="`background-image: url(${avatar})`"
52+
/>
53+
</template>
54+
<template v-else>
55+
<Avatar
56+
class=""
57+
:title="false"
58+
:size="32"
59+
variant="beam"
60+
:name="props.address"
61+
:square="false"
62+
/>
63+
</template>
64+
</div>
65+
</template>
66+
67+
<style scoped>
68+
.posts-username {
69+
overflow: hidden;
70+
display: -webkit-box;
71+
-webkit-box-orient: vertical;
72+
-webkit-line-clamp: 2;
73+
}
74+
</style>

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const getPagePaths = (async (
7070
adminRolePoints,
7171
rpcUrl,
7272
feeds,
73+
postsPluginId: postsPlugin?.id,
7374
}
7475

7576
return [

yarn.lock

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5299,6 +5299,16 @@ remark-stringify@^11.0.0:
52995299
mdast-util-to-markdown "^2.0.0"
53005300
unified "^11.0.0"
53015301

5302+
remark@^15.0.1:
5303+
version "15.0.1"
5304+
resolved "https://registry.yarnpkg.com/remark/-/remark-15.0.1.tgz#ac7e7563260513b66426bc47f850e7aa5862c37c"
5305+
integrity sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==
5306+
dependencies:
5307+
"@types/mdast" "^4.0.0"
5308+
remark-parse "^11.0.0"
5309+
remark-stringify "^11.0.0"
5310+
unified "^11.0.0"
5311+
53025312
require-directory@^2.1.1:
53035313
version "2.1.1"
53045314
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
@@ -5727,6 +5737,13 @@ strip-json-comments@~2.0.1:
57275737
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
57285738
integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
57295739

5740+
strip-markdown@^6.0.0:
5741+
version "6.0.0"
5742+
resolved "https://registry.yarnpkg.com/strip-markdown/-/strip-markdown-6.0.0.tgz#7d9fba3b25ddfa3859b928ecb08029ef0825aac5"
5743+
integrity sha512-mSa8FtUoX3ExJYDkjPUTC14xaBAn4Ik5GPQD45G5E2egAmeV3kHgVSTfIoSDggbF6Pk9stahVgqsLCNExv6jHw==
5744+
dependencies:
5745+
"@types/mdast" "^4.0.0"
5746+
57305747
sucrase@^3.32.0:
57315748
version "3.35.0"
57325749
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"

0 commit comments

Comments
 (0)