105 lines
2.4 KiB
Vue
105 lines
2.4 KiB
Vue
|
<template>
|
||
|
<div class="blog">
|
||
|
<header class="blog__header">
|
||
|
<h1><a href="/blog">Blog</a></h1>
|
||
|
</header>
|
||
|
|
||
|
<section class="blog__content">
|
||
|
<div class="blog__main-col">
|
||
|
<slot></slot>
|
||
|
</div>
|
||
|
|
||
|
<div class="blog__sidebar">
|
||
|
<BlogSidebar title="Tags">
|
||
|
<ul>
|
||
|
<li v-for="tag of tags">
|
||
|
<a :href="'/tags/' + tag.name">{{ tag.name }}</a>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</BlogSidebar>
|
||
|
|
||
|
<BlogSidebar title="Tag cloud">
|
||
|
<div class="tag-cloud">
|
||
|
<a
|
||
|
v-for="tag of tags"
|
||
|
:href="'/blog/tags/' + tag.name"
|
||
|
:style="{ fontSize: getFontSize(tag) }"
|
||
|
>{{ tag.name }}</a
|
||
|
>
|
||
|
</div>
|
||
|
</BlogSidebar>
|
||
|
|
||
|
<BlogSidebar title="Archive">
|
||
|
<ul>
|
||
|
<li v-for="archive of monthList">
|
||
|
<a :href="archive.href">{{ archive.name }}</a>
|
||
|
</li>
|
||
|
</ul>
|
||
|
</BlogSidebar>
|
||
|
</div>
|
||
|
</section>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script setup lang="ts">
|
||
|
const { data: tags } = await useFetch('/api/blog/tags');
|
||
|
const { data: archive } = await useFetch('/api/blog/archive');
|
||
|
|
||
|
const monthNames = [
|
||
|
'January',
|
||
|
'February',
|
||
|
'March',
|
||
|
'April',
|
||
|
'May',
|
||
|
'June',
|
||
|
'July',
|
||
|
'August',
|
||
|
'September',
|
||
|
'October',
|
||
|
'November',
|
||
|
'December',
|
||
|
];
|
||
|
|
||
|
const monthList = computed(() => {
|
||
|
let links = [];
|
||
|
const res = archive.value;
|
||
|
|
||
|
for (const year of Object.keys(res).sort((a, b) => Number(b) - Number(a))) {
|
||
|
for (const month of Object.keys(res[year]).sort(
|
||
|
(a, b) => Number(b) - Number(a)
|
||
|
)) {
|
||
|
const monthName = monthNames[new Date(`${year}-${month}-01`).getMonth()];
|
||
|
|
||
|
links.push({
|
||
|
name: `${monthName} ${year}`,
|
||
|
href: `/blog/archive/${year}/${month}`,
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return links;
|
||
|
});
|
||
|
|
||
|
const minTag = computed(() =>
|
||
|
tags.value.reduce<number>(
|
||
|
(min, current) => (min > current.count ? current.count : min),
|
||
|
100
|
||
|
)
|
||
|
);
|
||
|
|
||
|
const maxTag = computed(() =>
|
||
|
tags.value.reduce<number>(
|
||
|
(max, current) => (max < current.count ? current.count : max),
|
||
|
0
|
||
|
)
|
||
|
);
|
||
|
|
||
|
function convertRange(value: number, r1: number[], r2: number[]) {
|
||
|
return ((value - r1[0]) * (r2[1] - r2[0])) / (r1[1] - r1[0]) + r2[0];
|
||
|
}
|
||
|
|
||
|
const getFontSize = (tag: any): string => {
|
||
|
return convertRange(tag.count, [minTag.value, maxTag.value], [10, 20]) + 'px';
|
||
|
};
|
||
|
</script>
|