feat: init

This commit is contained in:
ccbikai
2024-08-04 20:42:51 +08:00
commit c39ab2d528
45 changed files with 12703 additions and 0 deletions

135
src/components/header.astro Normal file
View File

@@ -0,0 +1,135 @@
---
import { getEnv } from '../lib/env'
import voidFile from '../assets/void.png'
import rss from '../assets/rss.svg'
import podcast from '../assets/podcast.svg'
import twitter from '../assets/twitter.svg'
import github from '../assets/github.svg'
import discord from '../assets/discord.svg'
import telegram from '../assets/telegram.svg'
const { SITE_URL } = Astro.locals
const { channel } = Astro.props
const PODCASRT = getEnv(import.meta.env, Astro, 'PODCASRT')
const TWITTER = getEnv(import.meta.env, Astro, 'TWITTER')
const GITHUB = getEnv(import.meta.env, Astro, 'GITHUB')
const TELEGRAM = getEnv(import.meta.env, Astro, 'TELEGRAM')
const DISCORD = getEnv(import.meta.env, Astro, 'DISCORD')
const staticProxy = getEnv(import.meta.env, Astro, 'STATIC_PROXY') ?? '/static/'
---
<div id="header">
<a href={SITE_URL} title={channel?.title}>
<img
src={channel?.avatar?.startsWith('http')
? staticProxy + channel?.avatar
: voidFile.src}
alt={channel?.title}
class="header-avatar"
/>
</a>
<div class="header-title">
<a href={SITE_URL} class="site-title" title={channel?.title}>
{channel?.title}
</a>
</div>
<div class="header-icons">
<a
href={`${SITE_URL}rss.xml`}
target="_blank"
rel="alternate"
type="application/rss+xml"
title="RSS Feed"
>
<img {...rss} alt="RSS" class="social-icon" width="1em" />
</a>
{
PODCASRT && (
<a href={PODCASRT} target="_blank" title="Podcast">
<img {...podcast} alt="Podcast" class="social-icon" width="1em" />
</a>
)
}
{
TWITTER && TWITTER.length > 0 && (
<a
href={`https://twitter.com/${TWITTER}`}
title="Twitter"
target="_blank"
>
<img
{...twitter}
alt={`twitter.com/${TWITTER}`}
class="social-icon"
width="1em"
/>
</a>
)
}
{
GITHUB && GITHUB.length > 0 && (
<a href={`https://github.com/${GITHUB}`} title="Github" target="_blank">
<img
{...github}
alt={`github.com/${GITHUB}`}
class="social-icon"
width="1em"
/>
</a>
)
}
{
TELEGRAM && TELEGRAM.length > 0 && (
<a href={`https://t.me/${TELEGRAM}`} title="Telegram" target="_blank">
<img
{...telegram}
alt={`t.me/${TELEGRAM}`}
class="social-icon"
width="1em"
/>
</a>
)
}
{
DISCORD && DISCORD.length > 0 && (
<a href={DISCORD} title="Discord" target="_blank">
<img
{...discord}
alt="Discord Invite"
class="social-icon"
width="1em"
/>
</a>
)
}
</div>
</div>
{
channel?.description && channel?.description.length > 0 && (
<div class="text-box" id="site-intro">
{channel?.description}
</div>
)
}
<style>
#site-intro {
color: var(--secondary-color);
}
.social-icon {
padding: 4px;
}
.header-icons {
gap: 2px;
}
</style>

177
src/components/item.astro Normal file
View File

@@ -0,0 +1,177 @@
---
import dayjs from '../lib/dayjs'
import { getEnv } from '../lib/env'
const locale = getEnv(import.meta.env, Astro, 'LOCALE')
const timezone = getEnv(import.meta.env, Astro, 'TIMEZONE')
locale && dayjs.locale(locale)
const { SITE_URL } = Astro.locals
const { post } = Astro.props
const datetime = dayjs(post.datetime).tz(timezone)
const timeago = datetime.isBefore(dayjs().subtract(1, 'w'))
? datetime.format('HH:mm · ll · ddd')
: datetime.fromNow()
---
<div class="item" style={{ 'view-transition-name': `post-${post.id}` }}>
<div class="time-box">
<div class="dot"></div>
<div class="time">
<a
href={`${SITE_URL}posts/${post.id}`}
title={post.datetime}
class="item-link">{timeago}</a
>
</div>
</div>
{
post.content.length > 0 && (
<div class={`text-box content`} set:html={post.content} />
)
}
{
post.tags.length > 0 && (
<div
class="tag-box"
style={post.content.length === 0 ? 'padding-top: 30px;' : ''}
>
<div class="tag-icon" />
{post.tags.map((tag) => (
<a href={`/search/%23${tag}`} title={tag} class="tag">
{tag}
</a>
))}
</div>
)
}
</div>
<style>
.content {
word-break: break-word;
}
.content :global(img) {
width: calc(100% - var(--box-margin));
}
.content :global(.tgme_widget_message_link_preview) {
margin-top: 16px;
display: none;
.link_preview_site_name,
.link_preview_title,
.link_preview_description {
display: none;
}
}
.content
:global(.tgme_widget_message_link_preview):has(.link_preview_site_name) {
display: block;
background: var(--cell-background-color);
border-left: 3px solid var(--highlight-color);
padding: 6px;
padding-left: 10px;
border-radius: var(--box-border-radius);
.link_preview_title {
display: block;
font-size: 1em;
font-weight: bolder;
line-height: 2;
}
.link_preview_description {
display: block;
font-size: 0.8em;
line-height: 1.5;
}
}
.content :global(.tgme_widget_message_video) {
aspect-ratio: 1 / 1;
}
.content :global(.tgme_widget_message_link_preview):has(.link_preview_image) {
display: flex;
position: relative;
border: none;
padding: 0;
background: transparent;
.link_preview_image {
aspect-ratio: 1200 / 630;
object-fit: cover;
}
.link_preview_site_name {
display: block;
position: absolute;
bottom: var(--box-margin);
left: var(--box-margin);
padding-left: 4px;
padding-right: 4px;
background-color: rgba(0, 0, 0, 0.66);
font-size: 14px;
color: #fff;
line-height: 1.5;
border-radius: var(--box-border-radius);
text-overflow: ellipsis;
max-width: calc(100% - 28px);
white-space: nowrap;
overflow: hidden;
}
.link_preview_title,
.link_preview_description {
display: none;
}
}
.content :global(blockquote) {
margin: 16px 0;
font-size: 0.8em;
background: var(--cell-background-color);
border-left: 3px solid var(--highlight-color);
padding: 6px;
padding-left: 10px;
border-radius: var(--box-border-radius);
}
.content :global(.tgme_widget_message_sticker) {
display: block;
}
.item :global(.content):has(.tgme_widget_message_user_photo) {
display: flex;
.tgme_widget_message_user_photo {
width: 60px;
height: 60px;
}
}
.content :global(.tgme_widget_message_voice) {
display: block !important;
}
.content :global(.tgme_widget_message_poll_options) {
display: block;
.tgme_widget_message_poll_option_percent {
float: left;
margin-right: 8px;
}
}
.content :global(.tgme_widget_message_location_wrap) {
display: block;
.tgme_widget_message_location {
padding-top: 50%;
background: no-repeat center;
background-size: cover;
}
}
</style>

49
src/components/list.astro Normal file
View File

@@ -0,0 +1,49 @@
---
import Layout from '../layouts/base.astro'
import Header from '../components/header.astro'
import Item from '../components/item.astro'
const { SITE_URL } = Astro.locals
const { channel, before = true, after = true } = Astro.props
const posts = channel.posts ?? []
const beforeCursor = posts[posts.length - 1]?.id
const afterCursor = posts[0]?.id
// const cursor = +Astro.params.cursor
---
<Layout channel={channel} id="main-container">
<slot name="header">
<Header channel={channel} />
</slot>
<div class="items">
{posts.map((post) => <Item post={post} />)}
</div>
<div class="pages-container">
{
before && beforeCursor > 20 ? (
<a
href={`${SITE_URL}before/${beforeCursor}`}
title="Before"
class="page"
>
Before
</a>
) : (
<span class="page-placeholder">&nbsp;</span>
)
}
<div class="pages-info"></div>
{
after && afterCursor ? (
<a href={`${SITE_URL}after/${afterCursor}`} title="After" class="page">
After
</a>
) : (
<span class="page-placeholder">&nbsp;</span>
)
}
</div>
</Layout>