Skip to content

Commit

Permalink
My blogs draft
Browse files Browse the repository at this point in the history
  • Loading branch information
d0rich committed Nov 26, 2023
1 parent a1b40eb commit b056948
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 2 deletions.
1 change: 1 addition & 0 deletions apps/d.d0rich.me/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@tonconnect/ui": "^2.0.0-beta.6",
"@vueuse/core": "^10.6.1",
"consola": "^3.2.3",
"dateformat": "^5.0.3",
"pinia": "^2.1.7",
"rehype-stringify": "^10.0.0",
"remark-parse": "^11.0.0",
Expand Down
3 changes: 3 additions & 0 deletions apps/d.d0rich.me/src/entities/blog/model/Blog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { NftCollectionMetadata } from '@d0rich/ton-contracts/wrappers/DSocialNetworkBlog'

export interface Blog extends Omit<NftCollectionMetadata, '$$type'> {}
23 changes: 23 additions & 0 deletions apps/d.d0rich.me/src/entities/blog/ui/BlogAvatar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import { computed } from 'vue'
import { createAvatar } from '@dicebear/core'
import { shapes } from '@dicebear/collection'
const props = defineProps({
address: {
type: String,
required: true
}
})
const avatar = computed(() => {
return createAvatar(shapes, {
seed: props.address
}).toString()
})
</script>

<template>
<!-- eslint-disable-next-line vue/no-v-html -->
<figure v-html="avatar" />
</template>
61 changes: 61 additions & 0 deletions apps/d.d0rich.me/src/entities/blog/ui/BlogPreviewCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script setup lang="ts">
import { RouterLink } from 'vue-router'
import { DWrapShape } from '@d0rich/esprit-design'
import type { Blog } from '../model/Blog'
import BlogAvatar from './BlogAvatar.vue'
defineProps<{
blog: Blog
address: string
}>()
</script>

<template>
<DWrapShape class="blog-preview-card" shape-class="blog-preview-card__shape">
<template #shape-content>
<div class="relative w-full h-full overflow-hidden">
<BlogAvatar
:address="address"
class="blog-preview-card__image"
:aria-label="`Cover for the blog ${blog.name} on D`"
/>
</div>
</template>
<RouterLink
:to="`/blog/${address}`"
class="block"
style="padding: var(--shape-card--dense__padding)"
>
<div class="p-2 prose dark:prose-invert">
<h2>{{ blog.name }}</h2>

<p>{{ blog.description }}</p>
</div>
</RouterLink>
</DWrapShape>
</template>

<style>
.blog-preview-card {
@apply scale-90 hover:scale-100 transition-transform;
}
.blog-preview-card__shape {
clip-path: var(--shape-card--dense);
@apply bg-black bg-opacity-70;
}
.blog-preview-card__image {
@apply absolute object-cover h-full
translate-x-2/3 translate-y-2/3 -rotate-45
transition-all;
}
.blog-preview-card:hover .blog-preview-card__image {
@apply translate-x-1/2 translate-y-1/2 opacity-10;
}
.blog-preview-card__link__tag {
@apply mx-1 text-lg font-bold bg-cyan-600;
}
</style>
91 changes: 90 additions & 1 deletion apps/d.d0rich.me/src/pages/MyBlogs.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,92 @@
<script setup lang="ts">
import { ref, type ComputedRef, onBeforeMount, watch } from 'vue'
import { consola } from 'consola'
import type { OpenedContract } from '@ton/ton'
import { DSocialNetworkBlog } from '@d0rich/ton-contracts/wrappers/DSocialNetworkBlog'
import { useTonConnectStore } from '../features/tonconnect/stores/tonConnectStore'
import { useOpenedContract } from '../features/tonconnect/composables/useOpenedContract'
import { useMasterContractStore } from '../features/master/stores/masterContractStore'
import BlogPreviewCard from '../entities/blog/ui/BlogPreviewCard.vue'
import type { Blog } from '../entities/blog/model/Blog'
const masterContractStore = useMasterContractStore()
const tonConnectStore = useTonConnectStore()
const masterContract = useOpenedContract(masterContractStore.latestContract)
const userBlogsContracts = ref<
ComputedRef<OpenedContract<DSocialNetworkBlog> | null>[]
>([])
const blogs = ref<{ address: string; blog: Blog }[]>([])
watch(userBlogsContracts, async () => {
console.log('Generating blogs')

Check warning on line 21 in apps/d.d0rich.me/src/pages/MyBlogs.vue

View workflow job for this annotation

GitHub Actions / test

Unexpected console statement
const userBlogs = userBlogsContracts.value
const dataPromises = userBlogs.map(async (blog) => {
if (!blog.value) {
consola.error('Failed to open Blog contract')
return {
address: '',
blog: {
name: 'Failed to fetch',
description: '',
image: ''
}
}
}
const data = await blog.value?.getGetBlogInfo()
return {
address: blog.value.address.toString(),
blog: data.collection_content
}
})
blogs.value = await Promise.all(dataPromises)
})
async function fetchUserBlogs() {
if (!tonConnectStore.isConnected) {
consola.error('User is not authorized')
return []
}
const dMaster = masterContract.value
if (!dMaster) {
consola.error('TON client is not initialized')
return []
}
const blogsCount = await dMaster.getGetBlogsCount()
const getUserBlogsPromises = Array.from(Array(Number(blogsCount)).keys()).map(
async (index) => {
const blogAddress = await dMaster.getGetBlogAddressByIndex(BigInt(index))
if (!blogAddress) return null
const blogContract = useOpenedContract(
DSocialNetworkBlog.fromAddress(blogAddress)
)
if (!blogContract.value) {
consola.error(`Failed to open Blog contract ${blogAddress.toString()}`)
return null
}
const owner = await blogContract.value.getOwner()
if (owner.toRawString() !== tonConnectStore.wallet) return null
return blogContract
}
)
const userBlogs = (await Promise.all(getUserBlogsPromises)).filter(
(blog) => blog !== null
)
return userBlogs as ComputedRef<OpenedContract<DSocialNetworkBlog> | null>[]
}
onBeforeMount(async () => {
userBlogsContracts.value = await fetchUserBlogs()
})
</script>

<template>
<h1>My blogs</h1>
<h1 class="prose dark:prose-invert">My blogs</h1>
<nav class="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
<BlogPreviewCard
v-for="blog in blogs"
:key="blog.address"
:blog="blog.blog"
:address="blog.address"
/>
</nav>
</template>
27 changes: 27 additions & 0 deletions apps/d.d0rich.me/src/shared/utils/dateformat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import dateFormat from 'dateformat'

export function dateToMonthYear(date: Date | string = new Date()) {
return dateFormat(date, 'mmm yyyy')
}

export function dateToDayMonthYear(date: Date | string = new Date()) {
return dateFormat(date, 'dd mmm yyyy')
}

export function monthDiff(d1: Date, d2: Date) {
let months
months = (d2.getFullYear() - d1.getFullYear()) * 12
months -= d1.getMonth()
months += d2.getMonth()
return months <= 0 ? 0 : months
}

export function formatYearMonthDateDiff(d1: Date, d2: Date) {
const allMonths = monthDiff(d1, d2) + 1
const months = allMonths % 12
const fullYears = (allMonths - months) / 12
const yearsPart =
fullYears > 0 ? `${fullYears} year${fullYears > 1 ? 's' : ''}` : ''
const monthPart = months > 0 ? `${months} month${months > 1 ? 's' : ''}` : ''
return (yearsPart + ' ' + monthPart).trim()
}
2 changes: 1 addition & 1 deletion apps/d.d0rich.me/src/widgets/SidebarMenu.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script setup lang="ts">
import { ref } from 'vue'
import { DBtn } from '@d0rich/esprit-design'
import UserAvatar from '../entities/user/ui/UserAvatar.vue'
import TonConnect from '../features/tonconnect/ui/TonConnect.vue'
import UserAvatar from '../features/user/ui/UserAvatar.vue'
import { useTonConnectStore } from '@/features/tonconnect/stores/tonConnectStore'
const tonConnectStore = useTonConnectStore()
Expand Down
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b056948

Please sign in to comment.