Add solitude

This commit is contained in:
IF-chan
2024-07-05 21:01:19 +08:00
parent 26d71c4fbc
commit 71758b9fce
289 changed files with 23277 additions and 0 deletions
@@ -0,0 +1,18 @@
.aside-content#aside-content
- var noSticky, Sticky
if(is_home())
- noSticky = theme.aside.home.noSticky.split(',')
- Sticky = theme.aside.home.Sticky.split(',')
else if(is_post())
- noSticky = theme.aside.post.noSticky.split(',')
- Sticky = theme.aside.post.Sticky.split(',')
else if(is_page() || is_archive() || is_tag() || is_category())
- noSticky = theme.aside.page.noSticky.split(',')
- Sticky = theme.aside.page.Sticky.split(',')
each item in noSticky
include ./asideSwitch.pug
.sticky_layout
if page.toc
include ./asideToc.pug
each item in Sticky
include ./asideSwitch.pug
@@ -0,0 +1,5 @@
if theme.google_adsense.enable && !theme.google_adsense.auto_ads && theme.google_adsense.aside_card
.card-widget.card-adsense
ins.adsbygoogle(style="display:block; text-align:center; min-height:120px; min-width: 100%", data-ad-layout="in-article", data-ad-format="fluid", hide-unfilled="true", data-ad-client=theme.google_adsense.client, data-ad-slot=theme.google_adsense.slot)
script.
(adsbygoogle = window.adsbygoogle || []).push({});
@@ -0,0 +1,8 @@
.card-widget.card-tags.card-archives.card-webinfo.card-allinfo
if theme.aside.tags.enable
include ./asideTag
hr
if theme.aside.archive.enable
include ./asideArchive
hr
include ./asideWebInfo
@@ -0,0 +1,11 @@
- var archive = theme.aside.archive
ul.card-archive-list
- var type = archive.type ? archive.type : 'year'
each value, key in getArchiveLength(type)
li.card-archive-list-item
a.card-archive-list-link(href=`/archives/${key}/`)
span.card-archive-list-date= key
.card-archive-list-count-group
span.card-archive-list-count= value
span.card-archive-list-count-unit= __('console.archive_unit')
@@ -0,0 +1,7 @@
.card-widget(class=custom.class, id=custom.id)
if !custom.no_head
.item-headline
i(class=custom.icon)
span=custom.title
div(class=custom.content_class ||'item-content', id=custom.content_id, style=custom.content_css)
!= custom.content_html
@@ -0,0 +1,5 @@
.card-widget.card-platform
#flip-wrapper
#flip-content
.face
.back.face
@@ -0,0 +1,86 @@
- const {style ,url} = theme.aside.card
.card-widget.card-info
.card-content
case style
when 0
.card-info-avatar.is-center
.author-info__top-group
.author-info__sayhi#author-info__sayhi(onclick="sco.changeSayHelloText()")= _p('sayhello.morning')
.avatar-img-group
img.avatar-img(alt=_p('aside.avatar'), src=theme.aside.card.author.img)
if theme.aside.card.author.sticker
.avatar-sticker
img.avatar-sticker-img(src=theme.aside.card.author.sticker, alt=_p('aside.sticker'))
.author-info__description_group
.author-info__description!= theme.aside.card.content
.author-info__description2!= theme.aside.card.content2
.author-info__bottom-group
a.author-info__bottom-group-left(href=url_for(theme.aside.card.url))
.author-info__name= config.author
.author-info__desc!= config.subtitle
.card-info-social-icons.is-center
each value, label in theme.aside.card.information || {}
- var array = value.split('||')
a.social-icon(href=url_for(trim(array[0])), title=label)
i.solitude(class=array[1])
when 1
.card-info-bg-top
.is-center
.author-info__top-group
.author-info__sayhi#author-info__sayhi(onclick="sco.changeSayHelloText()")= _p('sayhello.morning')
a.card-info-avatar(href=url_for(theme.aside.card.url) title=_p('aside.avatar'))
.avatar-img
img(src=theme.aside.card.author.img alt=_p('aside.avatar'))
if theme.aside.card.author.sticker
.avatar-sticker
img.avatar-sticker-img(src=theme.aside.card.author.sticker, alt=_p('aside.sticker'))
.card-info__desc_group
.author-info__name= config.author
.author-info__desc!= config.subtitle
.card-info__data.is-center
a(href=url_for('/archives/') title=_p('aside.card.posts') + site.posts.length)
.length-num= site.posts.length
.headline= _p('page.archives')
a(href=url_for('/tags/') title=_p('aside.card.tags') + site.tags.length)
.length-num= site.tags.length
.headline= _p('page.tag')
a(href=url_for('/categories/') title=_p('aside.card.categories') + site.categories.length)
.length-num= site.categories.length
.headline= _p('page.category')
.card-info-social-icons.is-center
each value, label in theme.aside.card.information || {}
- var array = value.split('||')
a.social-icon(href=url_for(trim(array[0])), title=label)
i.solitude(class=array[1])
when 2
.card-info-bg-top
.author-info-social
.social-icons
each value, label in theme.aside.card.information || {}
- var array = value.split('||')
a.social-icon(href=url_for(trim(array[0])), title=label)
i.solitude(class=array[1])
span.more-info(onclick="document.querySelector('.social-icons').classList.toggle('show')")
i.solitude.st-more-2-fill
a.card-info-avatar(href=url_for(theme.aside.card.url) title=_p('aside.avatar'))
.avatar-img
img(src=theme.aside.card.author.img alt=_p('aside.avatar'))
if theme.aside.card.author.sticker
.avatar-sticker
img.avatar-sticker-img(src=theme.aside.card.author.sticker, alt=_p('aside.sticker'))
.author-info__name= config.author
.card-info__data.is-center
a(href=url_for('/archives/') title=_p('aside.card.posts') + site.posts.length)
.length-num= site.posts.length
.headline= _p('page.archives')
a(href=url_for('/tags/') title=_p('aside.card.tags') + site.tags.length)
.length-num= site.tags.length
.headline= _p('page.tag')
a(href=url_for('/categories/') title=_p('aside.card.categories') + site.categories.length)
.length-num= site.categories.length
.headline= _p('page.category')
.card-info__desc_group
.author-info__description!= theme.aside.card.content
.author-info__description2!= theme.aside.card.content2
@@ -0,0 +1,16 @@
.card-widget.card-recent-post
.item-headline
i.solitude.st-map-line
span= _p('aside.newpost')
.aside-list
- let index = 1
each post in site.posts.data.sort((a, b) => b.date < a.date ? -1 : 1)
if index <= 5
.aside-list-item
a.thumbnail(href=url_for(post.path) title=post.title)
img(alt=post.title src=post.cover)
.content
a.title(href=url_for(post.path) title=post.title)= post.title
if post.categories.data[0]
a.article-recent_post_categories(href=url_for(post.path))= post.categories.data[0].name
- index++
@@ -0,0 +1,9 @@
.card-widget.card-recent-comment
.item-headline
i.solitude.st-chat-fill
span= _p('aside.newcomment')
if theme.recent_comments.enable
a.recent-comment-more(href=url_for(theme.recent_comments.page) title=_p('console.recent_comment_more'))
i.solitude.st-right-btn-fill
.aside-list
include ../third-party/news-comment/newest-comment.pug
@@ -0,0 +1,19 @@
case item
when 'about'
include ./asideInfoCard.pug
when 'flip'
include ./asideFlipCard.pug
when 'newestPost'
include ./asideNewestPost.pug
when 'allInfo'
include ./asideAllInfo.pug
when 'ads'
include ./asideAdsense.pug
when 'newest_comment'
include ./asideNewstComments.pug
default
- const custom = site.data?.aside?.find((i) => i.name === item)
if custom
include ./asideCustom.pug
else
include ../../page/default.pug
@@ -0,0 +1,16 @@
- const highlight = theme.aside.tags.highlight_list || []
.card-tag-cloud
each tag in site.tags.find({ parent: { $exists: false } }).data
if highlight.includes(tag.name)
a.highlight(href=url_for(tag.path))= tag.name
sup= tag.length
else
a(href=url_for(tag.path))= tag.name
sup= tag.length
if site.tags.length >= theme.aside.tags.limit
span#more-tags-btn(onclick="sco.openAllTags()")= __('aside.tagmore')
else
style.
.card-tag-cloud::after {
display: none !important;
}
@@ -0,0 +1,5 @@
.card-widget#card-toc
.item-headline
i.solitude.st-menu-line
span= __('aside.toc')
.toc-content#toc-content!= toc(page.content, { list_number: false })
@@ -0,0 +1,48 @@
.webinfo
if theme.aside.siteinfo.postcount
.webinfo-item
.webinfo-item-title
i.item-icon.solitude.st-folder-fill
.item-name= __('aside.postcount')
.item-count= site.posts.length
if theme.busuanzi
if theme.aside.siteinfo.pv
.webinfo-item
.webinfo-item-title
i.item-icon.solitude.st-visitor-line
.item-name= __('aside.pv')
if theme.busuanzi_use === 0
span#busuanzi_value_site_pv
i.solitude.st-loading-line
else
span#busuanzi_site_pv
i.solitude.st-loading-line
if theme.aside.siteinfo.uv
.webinfo-item
.webinfo-item-title
i.item-icon.solitude.st-team-fill
.item-name= __('aside.uv')
if theme.busuanzi_use === 0
span#busuanzi_value_site_uv
i.solitude.st-loading-line
else
span#busuanzi_site_uv
i.solitude.st-loading-line
if theme.aside.siteinfo.runtimeenable
.webinfo-item
.webinfo-item-title
i.item-icon.solitude.st-calendar-todo-fill
.item-name= __('aside.runtime')
.item-count#runtimeshow
if theme.aside.siteinfo.updatetime
.webinfo-item
.webinfo-item-title
i.item-icon.solitude.st-loop-left-fill
.item-name= __('aside.updatetime')
time.item-count(datetime=new Date())
if theme.wordcount && theme.aside.siteinfo.wordcount
.webinfo-item
.webinfo-item-title
i.item-icon.solitude.st-word-fill
.item-name= __('aside.wordcount')
.item-count= totalcount(site)
@@ -0,0 +1,23 @@
div.banners-title
div.banners-title-big!= theme.hometop.banner.title
div.banners-title-small= theme.hometop.banner.url
- var group = theme.hometop.group
if group
div.banners-links
each value,label in group
- var array = value.split('||')
a.banners-link-btn(href=url_for(trim(array[0])) style=`background-image: ${array[2]} `)
if array[1]
i.solitude(class=array[1])
.banners-link-title= label
div.tags-group-all
.tags-group-wrapper
each i in [1,2]
- var keys = Object.keys(theme.hometop.banner.icon)
- var pairs = keys.map((val, i) => i % 2 ? [keys[i - 1], val] : []).filter(x => x.length)
each pair in pairs
.tags-group-icon-pair
each key in pair
.tags-group-icon(style=`background: ${theme.hometop.banner.icon[key].color}`)
img.nolazyload(src=theme.hometop.banner.icon[key].img, title=key)
@@ -0,0 +1,18 @@
.bbTimeList.container#bbTimeList(class=is_home_first_page() ? '' : 'more-page')
i.bber-logo.solitude.st-bblogo(onclick=`pjax.loadUrl('/essay/')`)
.swiper-container.swiper-no-swiping.swiper-container-initialized.swiper-container-vertical.swiper-container-pointer-events#bbtalk(tabindex="-1" onclick=`pjax.loadUrl('/essay/')`)
.swiper-wrapper#bber-talk
each item, i in site.data.essay.essay_list.slice(0, 10)
.li-style.swiper-slide
| #{item.content}
if item.image
i.solitude.st-image-fill
else if item.aplayer
i.solitude.st-disc-fill
else if item.video
i.solitude.st-video-fill
else if item.bilibili
i.solitude.st-bilibili-line
else if item.link
i.solitude.st-links
i.bber-gotobb.solitude.st-right-btn-fill(title=_p('home.bbtime.text') onclick=`pjax.loadUrl('/essay/')`)
@@ -0,0 +1,72 @@
- let recommends = site.posts.data.filter(item => item.recommend === true).slice(0,6) || false
if recommends
.recent-post-item#swiperBox
div.blog-slider.swiper-container-fade.swiper-container-horizontal#swiper_container
.blog-slider__wrp.swiper-wrapper
each item,index in recommends
.blog-slider__item.swiper-slide(onclick="pjax.loadUrl('"+item.path+"')")
.blog-slider__img
img(src=item.cover, alt=item.title)
.blog-slider__content
span.blog-slider__title=item.title
case theme.index_post_list.content
when false
break
when 1
span.blog-slider__desc= item.description
when 2
if item.description
span.blog-slider__desc= item.description
else
- const content = strip_html(item.content)
- let expert = content.substring(0, theme.index_post_list.length).replace(/\d+/g, '').replace(/&#xF/g, '').replace(/&#x/g, '')
- content.length > theme.index_post_list.length ? expert += ' ...' : ''
.span.blog-slider__desc= expert
default
- const content = strip_html(item.content)
- let expert = content.substring(0, theme.index_post_list.length).replace(/\d+/g, '').replace(/&#xF/g, '').replace(/&#x/g, '')
- content.length > theme.index_post_list.length ? expert += ' ...' : ''
.span.blog-slider__desc= expert
div.article-meta-wrap
span.article-meta.tags
each tag in item.tags.data
a.article-meta__tags(href=url_for(tag.path), onclick="event.stopPropagation();")
span.tags-punctuation=tag.name
span.post-meta-date
time(datetime=moment(item.date))
.blog-slider__pagination.swiper-pagination-clickable.swiper-pagination-bullets
script.
function carousel_swiper() {
let e = new Swiper(".blog-slider", {
direction: "vertical",
passiveListeners: true,
loop: true,
autoplay: {
disableOnInteraction: true,
delay: 5e3
},
pagination: {
el: ".blog-slider__pagination",
clickable: true
},
effect: 'fade',
fadeEffect: {
crossFade: true
},
passiveListeners: true,
spaceBetween: 30,
watchSlidesProgress: true,
mousewheel: true
})
, t = document.getElementById("swiper_container");
null !== t && (t.onmouseenter = () => {
e.autoplay.stop()
}
,
t.onmouseleave = () => {
e.autoplay.start()
}
)
}
@@ -0,0 +1,15 @@
.category-bar-items#category-bar-items(class=is_home() ? 'home' : '')
.category-bar-item(class=is_home() ? 'select' : '', id="category-bar-home")
a(href=url_for('/'))= __('home.home')
.category-bar-item
a(href=url_for('/archives/'))= __('home.archives')
each item in site.categories.find({ parent: { $exists: false } }).data
.category-bar-item(class=select ? (select === item.name ? 'select' : '') : '', id=item.name)
a(href=url_for(item.path))= item.name
div.category-bar-right
- let categories = site.categories.find({parent: {$exists: false}})
- let wordcount = categories.map(category => category.name).join('').length
if wordcount > 40 || categories.data.length > 10
.category-bar-next#category-bar-next(onclick="sco.scrollCategoryBarToRight()")
i.solitude.st-show-right-line
a.category-bar-more(href=url_for('/categories/'))= __('more')
@@ -0,0 +1,7 @@
.recent-top-post-group#recent-top-post-group
.recent-post-top#recent-post-top
#bannerGroup
#banners
include ./banner.pug
.topGroup
include ./topGroup.pug
@@ -0,0 +1,81 @@
mixin cover
a(href=url_for(post.path), title=post.title)
img.post_bg(src=url_for(post.cover), alt=post.title)
mixin info
div.recent-post-info-top
div.recent-post-info-top-tips
if post.sticky && is_home()
span.article-meta.sticky-warp
i.solitude.st-thumbtack-solid.sticky.orange
span.sticky.orange= _p('home.sticky')
each category in post.categories.data
span.original= category.name
if post.prev == null && is_home()
span.original= _p('home.new')
a.unvisited-post(href=url_for(post.path))= _p('home.read')
a.article-title(href=url_for(post.path), title=post.title)= post.title
case theme.index_post_list.content
when false
break
when 1
.content!= post.description
when 2
if post.description
.content!= post.description
else
- const content = strip_html(post.content)
- let expert = content.substring(0, theme.index_post_list.length).replace(/\d+/g, '').replace(/&#xF/g, '').replace(/&#x/g, '')
- content.length > theme.index_post_list.length ? expert += ' ...' : ''
.content!= expert
default
- const content = strip_html(post.content)
- let expert = content.substring(0, theme.index_post_list.length).replace(/\d+/g, '').replace(/&#xF/g, '').replace(/&#x/g, '')
- content.length > theme.index_post_list.length ? expert += ' ...' : ''
.content!= expert
div.article-meta-wrap
span.article-meta.tags
each tag in post.tags.data
a.article-meta__tags(href=url_for(tag.path), onclick="event.stopPropagation();")
span.tags-punctuation=tag.name
span.post-meta-date
time(datetime=moment(post.date))
- const { direction, cover } = theme.index_post_list
if direction === 'row'
- var position = cover === 'both' ? index % 2 === 0 ? 0 : 1 : cover === 'left' ? 0 : 1
div.recent-post-item(onclick="pjax.loadUrl('" + url_for(post.path) + "')")
if direction === 'column'
div.post_cover
+cover()
div.recent-post-info
+info()
else
case position
when 0
div.post_cover
+cover()
div.recent-post-info
+info()
when 1
div.recent-post-info
+info()
div.post_cover
+cover()
if theme.google_adsense && theme.google_adsense.enable && theme.google_adsense.auto_ads === false && theme.google_adsense.post_card
- var ads_height = theme.index_post_list.direction === 'column' ? '401px;' : '280px;'
if (index + 1) % 3 === 0
div.recent-post-item.google-ads-warp
ins.adsbygoogle(style="display:block; text-align:center; min-width: 100%; height:" + ads_height, data-ad-layout="in-article", data-ad-format="fluid", hide-unfilled="true", data-ad-client=theme.google_adsense.client, data-ad-slot=theme.google_adsense.slot)
script.
(adsbygoogle = window.adsbygoogle || []).push({});
@@ -0,0 +1,32 @@
- var filteredPosts = site.posts.data.filter(item => item.recommend === true).slice(0,6)
.recent-post-group
each post in filteredPosts
.recent-post-item
.post_cover
a(href=url_for(post.path), title=post.title)
span.recent-post-top-text= _p('home.recommend')
img.post_bg(alt=post.title, src=post.cover)
.recent-post-info
a.article-title(href=url_for(post.path), title=post.title)= post.title
mixin todayCardContent
.todayCard-info
.todayCard-tips= theme.hometop.recommendList.sup
.todayCard-title= theme.hometop.recommendList.title
.todayCard-cover.nolazyload(style=`background: url('${theme.hometop.recommendList.img}') no-repeat center /cover`)
.banner-button-group
a.banner-button(onclick="window.event.cancelBubble=true;sco.hideTodayCard();")
i.solitude.st-add-fill
span.banner-button-text= _p('home.recommendmore')
case theme.hometop.recommendList.url.startsWith('/')
when true
.todayCard#todayCard(onclick=`pjax.loadUrl('${theme.hometop.recommendList.url}')`)
+todayCardContent()
when false
script.
function GoTodayCard() {
window.open("#{theme.hometop.recommendList.url}", "_blank");
}
.todayCard#todayCard(onclick="GoTodayCard()")
+todayCardContent()
@@ -0,0 +1,13 @@
- var menu = theme.nav.group
if menu
.back-menu-list-groups
each value, label in menu
.back-menu-list-group
.back-menu-list-title= label
.back-menu-list
each data, label in value
- var array = data.split('||')
a.back-menu-item(href=url_for(trim(array[0])), title=label)
if array[1]
img.nolazyload.back-menu-item-icon(src=trim(array[1]), alt=label)
span.back-menu-item-text= label
@@ -0,0 +1,20 @@
- var menu = theme.nav.menu
if menu
.menus_items
each value, label in menu
.menus_item
if typeof value !== 'object'
a.site-page(href=url_for(value))
span= label
else
a.site-page(href="javascript:void(0);")
span= label
ul.menus_item_child
each childValue, childLabel in value
li
- var array = childValue.split('||')
a.site-page.child(href=url_for(trim(array[0])))
if array[1]
i.solitude(class=array[1])
span= childLabel
@@ -0,0 +1,24 @@
- var custom = theme.nav.right.custom || []
each item in custom
.nav-button(id=item.id)
a.site-page(href=url_for(item.url) || 'javascript:void(0);', onclick=item.onclick, title=item.title || '')
i.solitude(class=item.icon || '')
if theme.nav.right.random
.nav-button#randomPost_button
a.site-page(onclick="toRandomPost()", title=_p('nav.randompost'), href="javascript:void(0);")
i.solitude.st-dice-line
if theme.search.enable
.nav-button#search-button
a.site-page.social-icon.search(href="javascript:void(0);", title=_p('nav.search'))
i.solitude.st-search-line
if theme.nav.right.console
.nav-button#nav-console
a.console_switchbutton(onclick="sco.showConsole()", title=_p('nav.console'), href="javascript:void(0);")
i.solitude.st-dashboard-fill
.nav-button#nav-totop(onclick="sco.toTop()")
a.totopbtn
i.solitude.st-arrow-up-line
span#percent= "0"
#toggle-menu
a.site-page
i.solitude.st-menu-line
@@ -0,0 +1,13 @@
- const authorinfo = site.data.about.authorinfo
if authorinfo
.author-info
.author-tag-left
each tag in authorinfo.leftTags
span.author-tag= tag
.author-img
img(src=authorinfo.image)
.author-tag-right
each tag in authorinfo.rightTags
span.author-tag= tag
.author-title= site.data.about.title
@@ -0,0 +1,39 @@
- award = site.data.about.award
- var sum = 0
if site.data.about.rewardList
.author-content
.author-content-item.single.reward
.author-content-item-tips= _p('award.thanks')
span.author-content-item-title= _p('award.title')
.author-content-item-description
!= award.description
.reward-list-all
each reward in site.data.about.rewardList
- sum += reward.money
.reward-list-item
.reward-list-item-name= reward.name
.reward-list-bottom-group
.reward-list-item-money(style=(reward.vip ? "background: var(--efu-vip);color: var(--efu-white)" : ""))
if reward.icon
i.solitude(class=reward.icon)
| ¥ #{reward.money}
time.datatime.reward-list-item-time(datetime=moment(reward.time).format())
if theme.post.award.enable
.post-reward
.post-reward(onclick="AddRewardMask()")
.reward-button(title=_p('award.tipping'))
i.solitude.st-hand-heart-fill
= _p('award.tipping')
.reward-main
ul.reward-all
span.reward-title= theme.post.award.title
ul.reward-group
- var rewards = theme.post.award.list
each reward in rewards
li.reward-item
a(href=url_for(reward.url))
img.post-qr-code-img(alt=reward.name, src=reward.qcode, style="border-color:" + reward.color)
.post-qr-code-desc= reward.name
.reward-list-tips
p= award.tips.replace('{sum}', sum.toFixed(2))
@@ -0,0 +1,39 @@
- const contentinfo = site.data.about.contentinfo
if contentinfo
.author-content
.author-content-item.myInfoAndSayHello
.title1= contentinfo.sup
.title2
span.inline-word= contentinfo.name
.title1= contentinfo.title
.aboutsiteTips.author-content-item
.author-content-item-tips= contentinfo.tip
h2
span.inline-word!= contentinfo.slogan
.mask
each item,index in contentinfo.mask
if index === 0
span.first-tips(data-show='')= item
else if index === contentinfo.mask.length - 1
span(data-up='')= item
else
span= item
script.
var pursuitInterval = null;
pursuitInterval = setInterval(function () {
const show = document.querySelector('span[data-show]')
const next = show.nextElementSibling || document.querySelector('.first-tips')
const up = document.querySelector('span[data-up]')
if (up) {
up.removeAttribute('data-up')
}
show.removeAttribute('data-show')
show.setAttribute('data-up', '')
next.setAttribute('data-show', '')
}, 2000)
document.addEventListener('pjax:send', function () {
clearInterval(pursuitInterval);
});
@@ -0,0 +1,37 @@
- var game1 = site.data.about.game1
- var game2 = site.data.about.game2
if game1 || game2
.author-content
if game1
.author-content-item.game-apex(style=`background: url(${game1.img}) no-repeat top; background-size: cover;`)
.card-content
.author-content-item-tips= game1.title
span.author-content-item-title= game1.subtitle
.content-bottom
.tips= game1.tips_left
.tips= game1.tips_right
if game2
.author-content-item.game-jl(style=`background: url(${game2.img}) no-repeat top; background-size: cover;`)
.card-content
.author-content-item-tips= game2.title
span.author-content-item-title= game2.subtitle
.content-bottom
.tips= game2.tips_left
.tips= game2.tips_right
if site.data.about.likes
- const likes = site.data.about.likes
.author-content
each like in likes
.author-content-item(class=like.type, style=`background: url(${like.bg}) no-repeat center;`)
.card-content
.author-content-item-tips= like.tips
span.author-content-item-title= like.title
.content-bottom
.tips= like.subtips
if like.button
.banner-button-group
a.banner-button(href=url_for(like.button_link))
i.solitude.st-right-btn-fill
span.banner-button-text= like.button_text
@@ -0,0 +1,22 @@
- const motto = site.data.about.motto
- const expertise = site.data.about.expertise
if motto || expertise
.author-content
if motto
.author-content-item.maxim
.author-content-item-tips= motto.title
span.maxim-title
span= motto.prefix
span= motto.content
if expertise
.author-content-item.buff
.card-content
.author-content-item-tips= expertise.title
span.buff-title
span
| #{expertise.prefix}
span.inline-word= expertise.specialist
span
| #{expertise.content}
span.inline-word= expertise.level
@@ -0,0 +1,89 @@
- var tj = site.data.about.tj
- var oneself = site.data.about.oneself
if tj || oneself
.author-content
if tj
.about-statistic.author-content-item(style=`background: url(${tj.img});`)
.card-content
.author-content-item-tips=_p('about.other.tj.tip')
span.author-content-item-title=_p('about.other.tj.title')
#statistic
.post-tips
= _p('about.other.tj.post_tip')
case tj.provider
when '51la'
a(href="https://v6.51.la/") 51la网站统计
when 'baidu'
a(href="https://tongji.baidu.com/") 百度统计
if tj.button
.banner-button-group
a.banner-button(href=url_for(tj.button_link))
i.solitude.st-right-btn-fill
span.banner-button-text= tj.button_text
case tj.provider
when '51la'
script.
fetch("#{tj.url}")
.then(res => res.text())
.then(data => {
const title = ["最近活跃", "今日人数", "今日访问", "昨日人数", "昨日访问", "本月访问", "总访问量"];
let num = data.match(/(<\/span><span>).*?(\/span><\/p>)/g);
num = num.map(el => {
let val = el.replace(/(<\/span><span>)/g, "");
return val.replace(/(<\/span><\/p>)/g, "");
});
const s = document.getElementById("statistic");
let html = '';
for (let i = 0; i < num.length; i++) {
if (i === 0 || i === num.length - 1) continue;
html += `<div><span>${title[i]}</span><span id="${title[i]}">${num[i]}</span></div>`;
}
s.innerHTML = html;
});
when 'baidu'
script.
fetch("#{tj.url}")
.then(res => res.json())
.then(data => {
const title = {"today_uv": "今日人数", "today_pv": "今日访问", "yesterday_uv": "昨日人数", "yesterday_pv": "昨日访问", "last_month_pv": "最近月访问", "last_year_pv": "最近年访问"};
let s = document.getElementById("statistic");
for (let key in data) {
if (data.hasOwnProperty(key) && title[key]) {
s.innerHTML += `<div><span>${title[key]}</span><span id="${key}">${data[key]}</span></div>`;
}
}
});
if oneself
style.
:root {
--site-about-oneself-map--light: url(#{oneself.map.light});
--site-about-oneself-map--dark: url(#{oneself.map.dark});
}
.author-content-item-group.column.mapAndInfo
.author-content-item.map.single
span.map-title=_p('about.other.oneself.map_title') + oneself.location
.author-content-item.selfInfo.single
div
span.selfInfo-title=_p('about.other.oneself.info_title1')
span.selfInfo-content(style="color: #43a6c6;")= oneself.birthYear
div
span.selfInfo-title= oneself.university
span.selfInfo-content(style="color: #c69043;")= oneself.major
div
span.selfInfo-title=_p('about.other.oneself.info_title2')
span.selfInfo-content(style="color: #b04fe6;")= oneself.occupation
- var cause = site.data.about.cause
if cause
.author-content
.create-site-post.author-content-item.single
.author-content-item-tips= cause.tip
span.author-content-item-title= cause.title
!= cause.content
@@ -0,0 +1,17 @@
- const personalities = site.data.about.personalities
if personalities
.author-content
.author-content-item.personalities
.author-content-item-tips= personalities.tips
span.author-content-item-title= personalities.title
.title2(style=`color:${personalities.color}`)= personalities.type
.image
img.nolazyload(src=personalities.image)
.post-tips
= _p('about.personalities.tip1') + ' '
a(href='https://www.16personalities.com/')= personalities.linkText + ' '
= _p('about.personalities.tip2') + ' '
a(href=personalities.typeLink)= personalities.typeName
.author-content-item.myphoto
img.author-content-img(src=personalities.myphoto, alt="my photo")
@@ -0,0 +1,42 @@
- var skills = site.data.about.skills
- var careers = site.data.about.careers
if skills || careers
.author-content
if skills
.author-content-item.skills
.card-content
.author-content-item-tips= skills.title
span.author-content-item-title= skills.subtitle
.skills-style-group
.tags-group-all
.tags-group-wrapper
each i in [1,2]
- var pair = []
each tag, index in skills.tags
- pair.push(tag)
if pair.length === 2 || index === skills.tags.length - 1
.tags-group-icon-pair
each item in pair
.tags-group-icon(style=`background:${item.color}`)
img(src=item.icon, title=item.title)
- pair = []
.skills-list
each tag in skills.tags
.skill-info
.skill-icon(style=`background:${tag.color}`)
img(src=tag.icon, title=tag.title)
.skill-name
span= tag.title
.etc ...
if careers
.author-content-item.careers
.card-content
.author-content-item-tips= careers.title
span.author-content-item-title= careers.subtitle
.careers-group
each item in careers.items
.careers-item
.circle(style=`background:${item.color}`)
.name= `${item.school}, ${item.major}`
img.author-content-img(src=careers.image, alt=careers.title)
@@ -0,0 +1,48 @@
- var tenyear = site.data.about.tenyear
if tenyear
.author-content#tenyear
.create-site-post.author-content-item.single
.author-content-item-tips=tenyear.tips
.author-content-item-title=tenyear.title
p=tenyear.text
.tenyear-timeline
.progress
.past-time
.percentage-label
.time-labels
.start-time#tenyear-start-time= tenyear.start
.end-time#tenyear-end-time= tenyear.end
script.
function parseDateString(e) {
return e.replace(/年|月/g, '-').replace(/日/g, '');
}
function tenYear() {
let progressElement = document.querySelector(".progress");
let pastTimeElement = document.querySelector(".past-time");
let percentageLabelElement = document.querySelector(".percentage-label");
let startTimeElement = document.getElementById("tenyear-start-time");
let endTimeElement = document.getElementById("tenyear-end-time");
let startTime = new Date(parseDateString(startTimeElement.textContent)).getTime();
let endTime = new Date(parseDateString(endTimeElement.textContent)).getTime();
function updateProgress() {
let currentTime = new Date().getTime();
let progress = ((currentTime - startTime) / (endTime - startTime) * 100);
let progressPercentage = progress <= 100 ? progress + "%" : "100%";
pastTimeElement.style.setProperty("--past-time-percentage", progress + "%");
progressElement.style.setProperty("--progress-percentage", progressPercentage);
if(progress > 5){
percentageLabelElement.textContent = `${progress.toFixed(0)}%`;
percentageLabelElement.style.left = `calc(${progress}% - 35px)`;
}
}
percentageLabelElement.style.visibility = "visible";
updateProgress();
}
document.getElementById("tenyear") && tenYear() && window.Pjax.on('complete', tenYear)
@@ -0,0 +1,15 @@
.author-content.author-content-item.single.sharePage(style=`background: url(${page.cover}) no-repeat center; background-size: cover;`)
.card-content
.author-content-item-tips= page.desc
span.author-content-item-title= page.title
.content-bottom
if page.leftend
.tips= page.leftend
if page.rightend
.tips= page.rightend
if page.rightbtn
.banner-button-group
- const isInternalLink = page.rightbtnlink.startsWith('/')
a.banner-button(onclick=isInternalLink ? `pjax.loadUrl("${page.rightbtnlink}")`: null, href=isInternalLink ? null : url_for(page.rightbtnlink), target=isInternalLink ? null : "_blank")
i.solitude.st-right-btn-fill
span.banner-button-text= page.rightbtn
@@ -0,0 +1,23 @@
#equipment
if site.data.equipment
each i in site.data.equipment
.equipment-item
h2.equipment-item-title= i.class_name
.equipment-item-description= i.description
.equipment-item-content
each item in i.equipment_list
.equipment-item-content-item
.equipment-item-content-item-cover
img.equipment-item-content-item-image(src=item.image, alt=item.name)
.equipment-item-content-item-info
.equipment-item-content-item-name(onclick='utils.copy("' + item.name + '")')= item.name
.equipment-item-content-item-specification= item.specification
.equipment-item-content-item-description= item.description
if item.link
.equipment-item-content-item-toolbar
if item.link.includes('https://') || item.link.includes('http://')
a.equipment-item-content-item-link(href=item.link, target="_blank") 详情
else
a.equipment-item-content-item-link(href=item.link, target="_blank") 查看文章
a.bber-reply(onclick=`sco.toTalk('${item.description}')`)
i.solitude.st-chat-fill(style="font-size: 1rem;")
@@ -0,0 +1,31 @@
.banners-title
.banners-title-small= page.title
.banners-title-big= page.desc
.banner-button-group
if theme.footer.randomlink
a.banner-button.secondary(onclick="travelling()")
i.solitude.st-signal-tower-fill
span.banner-button-text=_p('link.banner.random')
if theme.comment.use
a.banner-button(onclick="sco.scrollToComment()")
i.solitude.st-right-btn-fill
span.solitude.banner-button-text=_p('link.banner.toComment')
.tags-group-all.nowrapMove
.tags-group-wrapper
- const data = site.data.links.links
- for (let i = 0; i < 2; i++)
each x in data
if x.type === "item"
- var pairs = []
each y, index in x.link_list
if (index % 2 === 0)
- pairs.push([y])
else
- pairs[pairs.length - 1].push(y)
each pair in pairs
.tags-group-icon-pair
each y in pair
a.tags-group-icon(href=url_for(y.link), title=y.name)
img(src=y.avatar + (site.data.links.banner_suffix || ''), title=y.name)
@@ -0,0 +1,15 @@
.site-card-group
each item in data.link_list
.site-card
if item.tag
span.site-card-tag(class=item.color)= item.tag
i.light
a.img(title=item.name, href=url_for(item.link))
img.flink-avatar(src=item.topimg + (data.topimg_suffix || ''), alt=item.name)
a.info.cf-friends-link(title=item.name, href=url_for(item.link))
.site-card-avatar
img.flink-avatar.cf-friends-avatar(src=item.avatar + (data.suffix || ''), alt=item.name)
.img-alt.is-center= item.name
.site-card-text
span.title.cf-friends-name= item.name
span.desc(title=item.descr)= item.descr
@@ -0,0 +1,8 @@
.flink-list.cf-friends-lost-contact.mini
each item in data.link_list
.flink-list-item
a.cf-friends-link(href="javascript:void(0);", title=item.name)
img.flink-avatar.cf-friends-avatar(alt=item.name, src=item.avatar + (data.suffix || ''))
.flink-item-info
span.flink-item-name.cf-friends-name= item.name
span.flink-item-desc(title=item.descr)= item.descr
@@ -0,0 +1,11 @@
.flink-list
each item in data.link_list
.flink-list-item
if item.tag
span.site-card-tag(class=item.color)= item.tag
i.light
a.cf-friends-link(href=url_for(item.link), title=item.name)
img.flink-avatar.cf-friends-avatar(alt=item.name, src=item.avatar + (data.suffix || ''))
.flink-item-info
span.flink-item-name.cf-friends-name= item.name
span.flink-item-desc(title=item.descr)= item.descr
@@ -0,0 +1,45 @@
- const { server, site, option } = theme.artalk
script(pjax).
(async () => {
const emojiReg = /<img [^>]+ atk-emoticon="[^"]+">/g
if (typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
const envel = new EasyDanmaku({
page: '!{theme.envelope.page}',
el: '#barrage',
line: !{line},
speed: !{speed},
hover: !{hover},
loop: !{loop},
})
const data = utils.saveToLocal.get('enevlope')
if (data) {
envel.batchSend(data, true)
return
}
const searchParams = new URLSearchParams({'site_name': "!{site}", 'limit': '100'})
await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`, {method: 'GET'}).then(async res => res.json())
.then(async data => {
let ls = []
for (const i of data.data) {
ls.push({
content: i.nick + ': ' + formatDanmaku(i.content),
avatar: '!{avatar}' + '/avatar/' + i.email_encrypted,
url: i.page_key + '#atk-comment-' + i.id,
})
}
envel.batchSend(ls, true)
utils.saveToLocal.set('enevlope', ls, .02)
}).catch(error => {
console.error("An error occurred while fetching comments: ", error)
})
function formatDanmaku(str) {
str = str.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
str = str.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
str = str.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
str = str.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
return str
}
})()
@@ -0,0 +1,9 @@
#article-container
!= page.content
if theme.envelope.enable
.switch_message
button.open(type='button' onclick="document.getElementById('barrage').classList.remove('hide')")
span(aria-hidden='true')= __('message.open')
button.close(type='button' onclick="document.getElementById('barrage').classList.add('hide')")
span(aria-hidden='true')= __('message.close')
#barrage
@@ -0,0 +1,12 @@
- const {use,avatar} = theme.comment
if use
case use[0]
when "Valine"
include ./valine
when "Twikoo"
include ./twikoo
when "Waline"
include ./waline
when "Artalk"
include ./artalk
@@ -0,0 +1,47 @@
- const {envId} = theme.twikoo
script(pjax).
(async () => {
const emojiReg = /<img class="tk-owo-emotion" [^>]+>/g
if (typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
const Danmaku = new EasyDanmaku({
page: '!{theme.envelope.page}',
el: '#barrage',
line: !{line},
speed: !{speed},
hover: !{hover},
loop: !{loop},
})
const data = utils.saveToLocal.get('enevlope')
if (data) {
Danmaku.batchSend(data, true)
return
}
let ls = []
fetch('!{envId}/', {
method: "POST",
body: JSON.stringify({
"event": "GET_RECENT_COMMENTS",
"includeReply": false,
"pageSize": 100
}),
headers: {'Content-Type': 'application/json'}
}).then(res => res.json()).then(({data}) => {
for (const i of data) {
if (i.avatar === undefined) i.avatar = '!{avatar}/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp'
ls.push({avatar: i.avatar, content: i.nick + ': ' + formatDanmaku(i.comment), url: i.url + '#' + i.id})
}
Danmaku.batchSend(ls, true);
utils.saveToLocal.set('envelope', ls, 0.02)
});
function formatDanmaku(str) {
str = str.replace(emojiReg, '!{__("console.newest_comment.emoji")}')
str = str.replace(/<\/*br>|[\s\uFEFF\xA0]+/g, '');
str = str.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
str = str.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
str = str.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
str = str.replace(/<.*?>/g, '');
return str
}
})()
@@ -0,0 +1,57 @@
- const {serverURLs,appId,appKey} = theme.valine
script(pjax).
(async () => {
const emojiReg = /:[a-z0-9_\u4e00-\u9fa5]+:/g
if(typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
const envel = new EasyDanmaku({
page: '!{theme.envelope.page}',
el: '#barrage',
line: !{line},
speed: !{speed},
hover: !{hover},
loop: !{loop},
})
const data = utils.saveToLocal.get('enevlope')
if(data){
envel.batchSend(data,true)
return
}
const url = new URL('!{serverURLs}/1.1/classes/Comment')
const params = {
url: window.location.pathname,
order: '-createdAt'
}
Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value))
try {
const res = await fetch(url, {
method: "GET",
headers: {
"X-LC-Id": "#{appId}",
"X-LC-Key": "#{appKey}",
"Content-Type": "application/json"
},
})
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`)
const data = await res.json()
const init = () =>
data.results.map(item => ({
content: item.nick + ': ' + formatDanmaku(item.comment),
avatar: '!{avatar}/avatar/'+md5(item.mail),
url: item.url
}))
if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
envel.batchSend(init(),true)
utils.saveToLocal.set('enevlope',init(),.02)
} catch (error) {
console.error("An error occurred while fetching comments: ", error)
}
function formatDanmaku(str) {
str = str.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
str = str.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
str = str.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
str = str.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
return str
}
})()
@@ -0,0 +1,42 @@
script(pjax).
(async () => {
const emojiReg = /<img [^>]+ class="wl-emoji">/g
if(typeof EasyDanmaku === "undefined") await utils.getScript('!{url_for(theme.cdn.envelope_js)}')
const envel = new EasyDanmaku({
page: '!{theme.envelope.page}',
el: '#barrage',
line: !{line},
speed: !{speed},
hover: !{hover},
loop: !{loop},
})
const data = utils.saveToLocal.get('enevlope')
if(data){
envel.batchSend(data,true)
return
}
await fetch('!{theme.waline.envId}/api/comment?type=recent&count=50', {method: 'GET'}).then(async res => res.json())
.then(async data => {
let ls = []
for (const i of data.data) {
ls.push({
content: i.nick + ': ' + formatContent(i.comment),
avatar: i.avatar,
url: i.url
})
}
envel.batchSend(ls,true)
utils.saveToLocal.set('enevlope',ls,.02)
}).catch(error => {
console.error("An error occurred while fetching comments: ", error)
})
function formatContent(content) {
content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
content = content.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
content = content.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
content = content.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
content = content.replace(/<.*?>/g, '');
return content
}
})()
@@ -0,0 +1,78 @@
- const { server, site, option } = theme.artalk
script(pjax).
(async () => {
document.querySelector('#comments-page').textContent = `#{__("loading")}`
const emojiReg = /<img [^>]+ atk-emoticon="[^"]+">/g
let cache = utils.saveToLocal.get('artalk-recent-comments')
if (cache) {
setHtml(document.querySelector('#comments-page'), cache)
return
}
let ls = []
const searchParams = new URLSearchParams({'site_name': "!{site}", 'limit': '!{limit}'})
await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`, {method: 'GET'}).then(async res => res.json())
.then(async data => {
for (const i of data.data) {
if (checkEmoji(i.content)) continue
let title = ''
if (i.page_key) {
await fetch(i.page_key).then(res => res.text()).then(html => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
title = doc.querySelector('title').innerText
}).catch(() => {
title = i.page_key
})
}
if (title.indexOf('|') > 0) {
title = title.split('|')[0]
}
ls.push({
title: title,
url: i.page_key + '#atk-comment-' + i.id,
nick: i.nick,
avatar: '!{avatar}' + '/avatar/' + i.email_encrypted,
time: i.date,
content: formatContent(i.content)
})
}
setHtml(document.querySelector('#comments-page'), ls)
utils.saveToLocal.set('artalk-recent-comments', ls, !{cache})
})
function setHtml(el, data) {
el.innerHTML = data.map(i => `
<div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
<div class="comment-info">
<img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
<div>
<span class="comment-user">${i.nick}</span>
</div>
<time class="comment-time" datetime="${i.time}"></time>
</div>
<div class="comment-content">${i.content}</div>
<div class="comment-title">
<i class="solitude st-chat-fill"></i>
${i.title}</div>
</div>
`).join('')
if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
else {
document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
}
}
function checkEmoji(content) {
return emojiReg.test(content)
}
function formatContent(content) {
content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
content = content.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
content = content.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
content = content.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
return content
}
})()
@@ -0,0 +1,83 @@
- const {envId} = theme.twikoo
script(pjax).
(async () => {
document.querySelector('#comments-page').textContent = `#{__("loading")}`
const emojiReg = /<img class="tk-owo-emotion" [^>]+>/g
let cache = utils.saveToLocal.get('twikoo-recent-comments')
if (cache) {
setHtml(document.querySelector('#comments-page'), cache)
return
}
let ls = []
await fetch('!{envId}', {
method: "POST",
body: JSON.stringify({
"event": "GET_RECENT_COMMENTS",
"includeReply": true,
"pageSize": !{limit}
}),
headers: {'Content-Type': 'application/json'}
}).then(res => res.json()).then(async ({data}) => {
for (const i of data) {
if (i.avatar === undefined) i.avatar = '!{avatar}/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp'
let title = ''
if (i.url) {
await fetch(i.url).then(res => res.text()).then(html => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
title = doc.querySelector('title').innerText
}).catch(() => {
title = i.url
})
}
if (title.indexOf('|') > 0) {
title = title.split('|')[0]
}
ls.push({
avatar: i.avatar,
nick: i.nick,
title: title,
content: i.comment,
url: i.url + '#' + i.id,
time: i.created
})
}
setHtml(document.querySelector('#comments-page'), ls)
utils.saveToLocal.set('twikoo-recent-comments', ls, !{cache})
});
function setHtml(el, data) {
el.innerHTML = data.map(i => `
<div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
<div class="comment-info">
<img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
<div>
<span class="comment-user">${i.nick}</span>
</div>
<time class="comment-time" datetime="${new Date(i.time)}"></time>
</div>
<div class="comment-content">${formatContent(i.content)}</div>
<div class="comment-title">
<i class="solitude st-chat-fill"></i>
${i.title}</div>
</div>
`).join('')
if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
else {
document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
}
}
function formatContent(content) {
content = content.replace(emojiReg, '!{__("console.newest_comment.emoji")}')
content = content.replace(/<\/*br>|[\s\uFEFF\xA0]+/g, '');
content = content.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
content = content.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
content = content.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
content = content.replace(/<.*?>/g, '');
return content
}
})()
@@ -0,0 +1,79 @@
- const { appId, appKey, serverURLs } = theme.valine
script(pjax).
(async () => {
document.querySelector('#comments-page').textContent = `#{__("loading")}`
const emojiReg = /:[a-z0-9_\u4e00-\u9fa5]+:/g
let cache = utils.saveToLocal.get('valine-recent-comments')
if (cache) {
setHtml(document.querySelector('#comments-page'), cache)
return
}
let ls = []
if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
await fetch('!{serverURLs}/1.1/classes/Comment?limit=8&order=-createdAt', {
method: "GET",
headers: {
"X-LC-Id": '!{appId}',
"X-LC-Key": '!{appKey}',
"Content-Type": "application/json"
}
}).then(async res => res.json()).then(async results => {
for (const i of results.results) {
let title = ''
if (i.url) {
await fetch(i.url).then(res => res.text()).then(html => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
title = doc.querySelector('title').innerText
}).catch(() => {
title = i.url
})
}
if (title.indexOf('|') > 0) {
title = title.split('|')[0]
}
ls.push({
title: title,
url: i.url,
nick: i.nick,
avatar: '!{avatar}' + '/avatar/' + md5(i.mail.trim().toLowerCase()),
time: i.createdAt,
content: formatContent(i.comment)
})
}
setHtml(document.querySelector('#comments-page'), ls)
utils.saveToLocal.set('valine-recent-comments', ls, !{cache})
})
function setHtml(el, data) {
el.innerHTML = data.map(i => `
<div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
<div class="comment-info">
<img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
<div>
<span class="comment-user">${i.nick}</span>
</div>
<time class="comment-time" datetime="${i.time}"></time>
</div>
<div class="comment-content">${i.content}</div>
<div class="comment-title">
<i class="solitude st-chat-fill"></i>
${i.title}</div>
</div>
`).join('')
if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
else {
document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
}
}
function formatContent(content) {
content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
content = content.replace(/!\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.image")}]')
content = content.replace(/\[.*?\]\((.*?)\)/g, '[!{__("console.newest_comment.link")}]')
content = content.replace(/```.*?```/g, '[!{__("console.newest_comment.code")}]')
return content
}
})()
@@ -0,0 +1,72 @@
script(pjax).
(async () => {
document.querySelector('#comments-page').textContent = `#{__("loading")}`
const emojiReg = /<img [^>]+ class="wl-emoji">/g
let cache = utils.saveToLocal.get('waline-recent-comments')
if (cache) {
setHtml(document.querySelector('#comments-page'), cache)
return
}
let ls = []
await fetch('!{theme.waline.envId}/api/comment?type=recent&count=!{limit}', {method: 'GET'}).then(async res => res.json())
.then(async data => {
console.log(data)
for (const i of data.data) {
let title = ''
if (i.url) {
await fetch(i.url).then(res => res.text()).then(html => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
title = doc.querySelector('title').innerText
}).catch(() => {
title = i.url
})
}
if (title.indexOf('|') > 0) {
title = title.split('|')[0]
}
ls.push({
title: title,
url: i.url,
nick: i.nick,
avatar: i.avatar,
time: new Date(i.time),
content: formatContent(i.comment)
})
}
setHtml(document.querySelector('#comments-page'), ls)
utils.saveToLocal.set('waline-recent-comments', ls, !{cache})
})
function setHtml(el, data) {
el.innerHTML = data.map(i => `
<div class="comment-card" title="${i.title}" onclick="pjax.loadUrl('${i.url}')">
<div class="comment-info">
<img src="${i.avatar}" class="nolazyload" alt="${i.nick}">
<div>
<span class="comment-user">${i.nick}</span>
</div>
<time class="comment-time" datetime="${i.time}"></time>
</div>
<div class="comment-content">${i.content}</div>
<div class="comment-title">
<i class="solitude st-chat-fill"></i>
${i.title}</div>
</div>
`).join('')
if (typeof sco !== 'undefined') sco.changeTimeFormat(document.querySelectorAll('.comment-time'))
else {
document.addEventListener('pjax:complete', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
document.addEventListener('DOMContentLoaded', () => sco.changeTimeFormat(document.querySelectorAll('.comment-time')))
}
}
function formatContent(content) {
content = content.replace(emojiReg, '[!{__("console.newest_comment.emoji")}]')
content = content.replace(/<img.*?>/g, '[!{__("console.newest_comment.image")}]');
content = content.replace(/<a.*?>.*?<\/a>/g, '[!{__("console.newest_comment.link")}]');
content = content.replace(/<pre.*?>.*?<\/pre>/g, '[!{__("console.newest_comment.code")}]');
content = content.replace(/<.*?>/g, '');
return content
}
})()
@@ -0,0 +1,44 @@
.post-reward
.reward-button(title=_p('award.tipping') onclick="AddRewardMask()")
i.solitude.st-hand-heart-fill
=_p('award.tipping')
.reward-main
ul.reward-all
span.reward-title=theme.post.award.title
ul.reward-group
- let list = theme.post.award.list || []
for item in list
li.reward-item
a(href=url_for(item.url))
img.post-qr-code-img.nolazyload(src=item.qcode, alt=item.name, style="border-color: " + item.color)
.post-qr-code-desc=item.name
a.reward-main-btn(href=url_for(theme.post.award.appreciators))
.reward-text= _p('award.title')
.reward-dec=theme.post.award.desc
script.
function RemoveRewardMask() {
let rewardMainElements = document.querySelectorAll(".reward-main");
let quitBoxElement = document.querySelector("#quit-box");
rewardMainElements.forEach(element => {
element.style.display = "none";
});
if (quitBoxElement) {
quitBoxElement.style.display = "none";
}
}
function AddRewardMask() {
let rewardMainElements = document.querySelectorAll(".reward-main");
let quitBoxElement = document.querySelector("#quit-box");
rewardMainElements.forEach(element => {
element.style.display = "flex";
});
if (quitBoxElement) {
quitBoxElement.style.display = "flex";
}
}
@@ -0,0 +1,74 @@
- const {copyright} = theme.post.default
.post-copyright
.post-copyright__author_group
a.post-copyright__author_img(href=url_for(copyright.author.url))
img.post-copyright__author_img_front(src=copyright.author.img || theme.site.icon)
.post-copyright__author_name= config.title
.post-copyright__author_desc= config.subtitle
.post-tools#post-tools
.post-tools-left
#quit-box(onclick="RemoveRewardMask()")
if theme.post.award.enable
include ./award
if theme.post.rss
.reward-link.mode
a.reward-link-button(href=url_for(theme.post.rss))
i.solitude.st-plant-fill
= _p('footer.rss')
if theme.post.share.enable
.social-share
- const path = config.url + url_for(page.path);
- const encodedPath = encodeURIComponent(path);
- const encodedTitle = encodeURIComponent(page.title);
- const encodedDescription = encodeURIComponent(page.description);
- const encodedIcon = encodeURIComponent(page.cover || theme.site.icon);
each item in theme.post.share.list || []
case item
when 'qq'
a.social-share-ico.icon-qq(href=`https://connect.qq.com/widget/shareqq/index.html?url=${encodedPath}&title=${encodedTitle}&desc=${encodedDescription}&summary=${encodedDescription}&site=${encodedTitle}&pics=${encodedIcon}` title=_p('post.share.qq'))
i.solitude.st-qq-fill
when 'weibo'
a.social-share-ico.icon-weibo(href=`http://service.weibo.com/share/share.php?url=${encodedPath}&title=${encodedTitle}&pic=${encodedIcon}` title=_p('post.share.weibo'))
i.solitude.st-weibo-fill
when 'telegram'
a.social-share-ico.icon-telegram(href=`https://t.me/share/url?url=${encodedPath}&text=${encodedTitle}` title=_p('post.share.telegram'))
i.solitude.st-telegram-fill
when 'whatsapp'
a.social-share-ico.icon-whatsapp(href=`https://api.whatsapp.com/send?text=${encodedTitle} ${encodedPath}` title=_p('post.share.whatsapp'))
i.solitude.st-whatsapp-fill
when 'linkedin'
a.social-share-ico.icon-linkedin(href=`https://www.linkedin.com/shareArticle?mini=true&url=${encodedPath}&title=${encodedTitle}&summary=${encodedDescription}&source=${encodedTitle}` title=_p('post.share.linkedin'))
i.solitude.st-linkedin-box-fill
when 'facebook'
a.social-share-ico.icon-facebook(href=`https://www.facebook.com/sharer/sharer.php?u=${encodedPath}` title=_p('post.share.facebook'))
i.solitude.st-facebook-fill
when 'twitter'
a.social-share-ico.icon-twitter(href=`https://twitter.com/intent/tweet?url=${encodedPath}&text=${encodedTitle}` title=_p('post.share.twitter'))
i.solitude.st-twitter-x-fill
when 'link'
.social-share-ico.icon-link(onclick=`utils.copy("${path}")` title=_p('post.share.link'))
i.solitude.st-links-line
when 'qrcode'
.social-share-ico.icon-qrcode(title=_p('post.share.qrcode'))
i.solitude.st-qr-code-fill
.share-main
.share-main-all
#qrcode
.reward-dec=_p('post.share.qrcode')
script(pjax).
typeof QRCode === 'function' && new QRCode(document.getElementById("qrcode"), '!{path}');
window.addEventListener('DOMContentLoaded', () => {
new QRCode(document.getElementById("qrcode"), '!{path}');
});
if copyright.enable || page.copyright
.post-copyright__notice
span.post-copyright-info
if page.reprint
= _p('post.copyright.reprint')
else
= _p('post.copyright.original')
a(href=url_for(theme.post.default.copyright.licenurl))
| #{theme.post.default.copyright.license}
= _p('post.copyright.original_end')
a(href=url_for("/")) #{config.title}
@@ -0,0 +1,12 @@
.post-ai
.ai-title
.ai-title-left
i.ai-title-icon.solitude.st-robot-fill
.ai-title-text=_p('post.ai.title')
.ai-tag#ai-tag= theme.post_ai.modelName
.ai-explanation(style="display: block;")
.ai-suggestions
.ai-bottom
.ai-tips= theme.post_ai.tips
if theme.post_ai.report
a.ai-report(title=_p('post.ai.tip'), href=url_for(theme.post_ai.report))=_p('post.ai.tip')
@@ -0,0 +1,84 @@
.coverdiv#coverdiv
img#post-cover.nolazyload(src=url_for(page.cover), alt=page.title)
#post-info
#post-firstinfo
.meta-firstline
- var cc = page.reprint ? _p('post.reprint') : _p('post.original')
a.post-meta-original(title=_p('post.cc').replace(/\$\{cc}/, cc))= cc
if page.categories.data.length > 0
span.post-meta-categories
a.post-meta-categories(href=url_for('/' + page.categories.data[0].path))= page.categories.data[0].name
.tag_share
.post-meta__tag-list
each tag in page.tags.data
a.post-meta__tags(href=url_for(tag.path))
span.tags-name.tags-punctuation= tag.name
h1.post-title= page.title
#post-meta
.meta-secondline
if theme.post.meta.date
span.post-meta-date(title=_p('post.posted') + ' ' + full_date(page.date))
i.post-meta-icon.solitude.st-calendar-todo-fill
time(datetime=date_xml(page.date))= date_xml(page.date)
if theme.post.meta.updated
span.post-meta-date(title=_p('post.updated') + ' ' + full_date(page.updated))
i.post-meta-icon.solitude.st-refresh-line
time(datetime=date_xml(page.updated))= date_xml(page.updated)
if theme.wordcount
span.post-meta-wordcount
if theme.post.meta.wordcount
i.post-meta-icon.solitude.st-word-fill(title=_p('post.wordcount'))
span.word-count= wordcount(page.content)
span.post-meta-separator
if theme.post.meta.readtime
i.post-meta-icon.solitude.st-clock-fill(title=_p('post.minread'))
span= min2read(page.content) + " min"
if theme.post.meta.locate
span.post-meta-position(title=_p('post.ip') + page.locate)
i.post-meta-icon.solitude.st-map-pin-fill
span= page.locate
if theme.post.meta.pv
a.post-meta-pv(href=url_for(page.path), title=_p('post.pv'))
i.post-meta-icon.solitude.st-fire-fill
if theme.comment.use && theme.comment.pv
case theme.comment.use[0]
when "Twikoo"
span#twikoo_visitors
i.solitude.st-loading-line
when "Waline"
span.waline-pageview-count
i.solitude.st-loading-line
when "Valine"
span.leancloud_visitors(id=url_for(page.path))
span.leancloud-visitors-count
i.solitude.st-loading-line
when 'Artalk'
span#ArtalkPV
i.solitude.st-loading-line
else
if theme.busuanzi
if theme.busuanzi_use === 0
span#busuanzi_value_page_pv
i.solitude.st-loading-line
else
span#busuanzi_page_pv
i.solitude.st-loading-line
if theme.post.meta.comment && page.comment && theme.comment.count && theme.comment.use
span.post-meta-commentcount(title=_p('post.comment'), onclick="sco.scrollTo('post-comment')")
i.solitude.st-chat-fill
a(href=url_for(page.path) + "#post-comment")
case theme.comment.use[0]
when "Twikoo"
span.twikoo-count
i.solitude.st-loading-line
when "Waline"
span.waline-comment-count
i.solitude.st-loading-line
when "Valine"
span.valine-comment-count(data-xid=url_for(page.path) itemprop="commentCount")
i.solitude.st-loading-line
when 'Artalk'
span.artalk-count
i.solitude.st-loading-line
include ./wave
@@ -0,0 +1,25 @@
nav.needEndHide.pagination-post#pagination
if page.prev && page.next
.prev-post.pull-left
a(href=url_for(page.prev.path))
.pagination-info
.label=_p('post.nav.prev')
.prev_info= page.prev.title
.next-post.pull-right
a(href=url_for(page.next.path))
.pagination-info
.label=_p('post.nav.next')
.next_info= page.next.title
else
if !page.prev && page.next
.next-post.pull-full
a(href=url_for(page.next.path))
div.pagination-info
.label=_p('post.nav.next')
.next_info= page.next.title
if !page.next && page.prev
.prev-post.pull-full
a(href=url_for(page.prev.path))
.pagination-info
.label=_p('post.nav.prev')
.prev_info= page.prev.title
@@ -0,0 +1,9 @@
section.main-hero-waves-area.waves-area
svg.waves-svg(xmlns="http://www.w3.org/2000/svg", xlink="http://www.w3.org/1999/xlink", viewBox="0 24 150 28", preserveAspectRatio="none", shape-rendering="auto")
defs
path#gentle-wave(d="M -160 44 c 30 0 58 -18 88 -18 s 58 18 88 18 s 58 -18 88 -18 s 58 18 88 18 v 44 h -352 Z")
g.parallax
use(href="#gentle-wave", x="48", y="0")
use(href="#gentle-wave", x="48", y="3")
use(href="#gentle-wave", x="48", y="5")
use(href="#gentle-wave", x="48", y="7")
@@ -0,0 +1,44 @@
- var datalinks = []
- var data = site.data.links.links
if(data)
each item in data
if item.type === "item"
each y in item.link_list
- datalinks.push({ name: y.name,link: y.link})
script.
const links = !{JSON.stringify(datalinks)}
const randomText = '!{_p('link.random')}'
function travelling() {
const link = links[utils.randomNum(links.length)];
Snackbar.show({
text: randomText.replace(/\$\{name}/,link.name),
duration: 8000,
pos: 'top-center',
actionText: '!{_p('link.to')}',
onActionClick: function(element) {
element.style.opacity = 0;
window.open(link.link, '_blank');
}
});
}
if theme.footer.randomlink
script.
function randomLinksList() {
const linkcard = document.getElementById('friend-links-in-footer');
if (linkcard == null) return;
let data = '';
let linksCopy = [...links];
let count = Math.min(3, linksCopy.length);
for (let i = 0; i < count; i++) {
let index = utils.randomNum(linksCopy.length);
const {link, name} = linksCopy[index];
data += `<a class="footer-item" href="${link}" target="_blank" rel="noopener noreferrer nofollow">${name}</a>`;
linksCopy.splice(index, 1);
}
linkcard.innerHTML = data + '<a class="footer-item" href="#{url_for(/links/)}">#{_p('more')}</a>';
}
@@ -0,0 +1,61 @@
- const { server, site, option } = theme.artalk
- const { lazyload ,use} = theme.comment
script.
(() => {
let artalkItem = null
const initArtalk = () => {
artalkItem = Artalk.init({
el: '#artalk-wrap',
server: '!{server}',
site: "!{site}",
pageKey: location.pathname,
darkMode: document.documentElement.getAttribute('data-theme') === 'dark'
}, !{JSON.stringify(option)})
if (GLOBAL_CONFIG.lightbox === 'null') return
artalkItem.on('list-loaded', () => {
const array = []
artalkItem.ctx.get('list').getCommentNodes().forEach(comment => {
array.push({
nick: comment.data.nick,
content: comment.data.content_marked,
mailMd5: comment.data.email_encrypted,
})
const $content = comment.getRender().$content
GLOBAL_CONFIG.lightbox && utils.lightbox($content.querySelectorAll('img:not([atk-emoticon])'))
})
sco.owoBig({body: '.atk-grp', item: '.atk-item'})
!{commentBarrage} && barrageArtalk(array)
})
const destroyArtalk = () => artalkItem.destroy()
utils.addGlobalFn('pjax', destroyArtalk, 'destroyArtalk')
}
const loadArtalk = async () => {
if (typeof Artalk === 'object') initArtalk()
else {
await utils.getCSS('!{theme.cdn.artalk_css}')
await utils.getScript('!{theme.cdn.artalk_js}').then(initArtalk)
}
}
const artalkChangeMode = theme => {
const artalkWrap = document.getElementById('artalk-wrap')
if (!(artalkWrap && artalkWrap.children.length)) return
const isDark = theme === 'dark'
artalkItem.setDarkMode(isDark)
}
utils.addGlobalFn('themeChange', artalkChangeMode, 'artalk')
if ('!{use[0]}' === 'Artalk' || !{lazyload}) {
if (!{lazyload}) utils.loadComment(document.getElementById('artalk-wrap'), loadArtalk)
else loadArtalk()
} else {
window.loadTwoComment = loadArtalk
}
})()
if commentBarrage
script.
async function barrageArtalk(array) {
const init = () => initializeCommentBarrage(array)
if (typeof initializeCommentBarrage === "undefined") await utils.getScript('!{url_for(theme.cdn.commentBarrage)}').then(init)
else init()
}
@@ -0,0 +1,44 @@
- const {use,count} = theme.comment
#post-comment
.comment-head
.comment-headline
i.solitude.st-chat-fill
span=' ' + _p('comment.title')
if count && is_post()
span.count
= ' ('
each name in use
case name
when "Twikoo"
span.twikoo-count
i.solitude.st-loading-line
when "Waline"
span.waline-comment-count
i.solitude.st-loading-line
when "Valine"
span.valine-comment-count(data-xid=url_for(page.path) itemprop="commentCount")
i.solitude.st-loading-line
when "Artalk"
span.artalk-count
| )
if use.length > 1
.comment-switch
span.first=use[0]
span#switch-btn
span.second=use[1]
.comment-wrap
each name in use
case name
when 'Valine'
#vcomment.vcomment
when 'Twikoo'
#twikoo-wrap
when 'Waline'
#waline-wrap
when 'Artalk'
#artalk-wrap
when 'Giscus'
#giscus-wrap
@@ -0,0 +1,60 @@
- const { repo, repo_id, category_id, theme:themes, option } = theme.giscus
- const giscusUrl = theme.cdn.giscus || 'https://giscus.app/client.js'
- const giscusOriginUrl = new URL(giscusUrl).origin
- const { use, lazyload } = theme.comment
script.
(()=>{
const getGiscusTheme = theme => {
return theme === 'dark' ? '!{themes.dark}' : '!{themes.light}'
}
const loadGiscus = () => {
const config = Object.assign({
src: '!{giscusUrl}',
'data-repo': '!{repo}',
'data-repo-id': '!{repo_id}',
'data-category-id': '!{category_id}',
'data-mapping': 'pathname',
'data-theme': getGiscusTheme(document.documentElement.getAttribute('data-theme')),
'data-reactions-enabled': '1',
crossorigin: 'anonymous',
async: true
},!{JSON.stringify(option)})
const ele = document.createElement('script')
for (let key in config) {
ele.setAttribute(key, config[key])
}
document.getElementById('giscus-wrap').appendChild(ele)
}
const changeGiscusTheme = theme => {
const sendMessage = message => {
const iframe = document.querySelector('iframe.giscus-frame')
if (!iframe) return
iframe.contentWindow.postMessage({ giscus: message }, '!{giscusOriginUrl}')
}
sendMessage({
setConfig: {
theme: getGiscusTheme(theme)
}
});
}
utils.addGlobalFn('themeChange', changeGiscusTheme, 'giscus')
if ('!{use[0]}' === 'Giscus' || !!{lazyload}) {
if (!{lazyload}) {
const giscusWrap = document.getElementById('giscus-wrap')
if (giscusWrap) {
utils.loadComment(giscusWrap, loadGiscus)
}
} else {
loadGiscus()
}
} else {
window.loadOtherComment = loadGiscus
}
})()
@@ -0,0 +1,14 @@
- const {use} = theme.comment
each name in use
case name
when 'Twikoo'
!=partial('includes/widgets/third-party/comments/twikoo', {}, {cache: true})
when 'Waline'
!=partial('includes/widgets/third-party/comments/waline', {}, {cache: true})
when 'Valine'
!=partial('includes/widgets/third-party/comments/valine', {}, {cache: true})
when 'Artalk'
!=partial('includes/widgets/third-party/comments/artalk', {}, {cache: true})
when 'Giscus'
!=partial('includes/widgets/third-party/comments/giscus', {}, {cache: true})
@@ -0,0 +1,80 @@
- const { envId, region, option ,accessToken } = theme.twikoo
- const { lazyload, count, use,commentBarrage } = theme.comment
script().
(() => {
const getCount = () => {
const ele = document.querySelectorAll('.twikoo-count')
if (!ele) return
twikoo.getCommentsCount({
envId: '!{envId}',
region: '!{region}',
urls: [window.location.pathname],
includeReply: false
}).then(res => {
ele.forEach(item => item.textContent = res[0].count)
}).catch(err => {
console.error(err)
})
}
const init = () => {
twikoo.init(Object.assign({
el: '#twikoo-wrap',
envId: '!{envId}',
region: '!{region}',
path: window.location.pathname,
onCommentLoaded: () => {
GLOBAL_CONFIG.lightbox && utils.lightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)'))
}
}, !{JSON.stringify(option)}))
!{count ? ' && getCount()' : ''}
sco.owoBig({
body: '.OwO-body',
item: '.OwO-items li'
})
barrageTwikoo()
}
const loadTwikoo = () => {
if (typeof twikoo === 'object') setTimeout(init,0)
else utils.getScript('!{url_for(theme.cdn.twikoo)}').then(init)
}
if ('!{use[0]}' === 'Twikoo' || !{lazyload}) {
if (!{lazyload}) utils.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo)
else loadTwikoo()
} else {
window.loadTwoComment = loadTwikoo
}
})()
if commentBarrage
script.
async function barrageTwikoo() {
await fetch("!{envId}", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
event: "COMMENT_GET",
accessToken: "!{accessToken}",
url: window.location.pathname
})
}).then(async res => {
if (!res.ok) throw new Error("HTTP error! status: " + res.status)
const data = await res.json();
const init = () => {
initializeCommentBarrage((data.data).map(item => Object.assign({
content: item.comment,
nick: item.nick,
mailMd5: item.mailMd5,
id: item.id
})))
}
if (typeof initializeCommentBarrage === "undefined") await utils.getScript('!{url_for(theme.cdn.commentBarrage)}').then(init)
else init()
}).catch(error => console.error("An error occurred while fetching comments: ", error))
}
@@ -0,0 +1,72 @@
- const { lazyload, count, use,commentBarrage } = theme.comment
- const { appId, appKey, avatar, serverURLs, visitor, option } = theme.valine
- let emojiMaps = '""'
if site.data.valine
- emojiMaps = JSON.stringify(site.data.valine)
script.
(() => {
const initValine = () => {
const valine = new Valine({
el: '#vcomment',
appId: '#{appId}',
appKey: '#{appKey}',
avatar: '#{avatar}',
serverURLs: '#{serverURLs}',
emojiMaps: !{emojiMaps},
path: window.location.pathname,
visitor: #{visitor},
...!{JSON.stringify(option)}
})
GLOBAL_CONFIG.lightbox && utils.lightbox(document.querySelectorAll('#comment .vcontent img:not(.vemoji)'))
sco.owoBig({body: '.vwrap', item: '.vemojis i'})
}
const loadValine = async () => {
if (typeof Valine === 'function') setTimeout(initValine, 0)
else {
await utils.getScript('!{url_for(theme.cdn.valine)}').then(initValine)
}
!{commentBarrage} && barrageValine()
}
if ('!{use[0]}' === 'Valine' || !{lazyload}) {
if (!{lazyload}) utils.loadComment(document.getElementById('vcomment'), loadValine)
else loadValine()
} else {
window.loadTwoComment = loadValine
}
})()
if commentBarrage
script.
async function barrageValine() {
const url = new URL('!{serverURLs}/1.1/classes/Comment')
const params = {
url: window.location.pathname,
order: '-createdAt'
}
Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value))
await fetch(url, {
method: "GET",
headers: {
"X-LC-Id": "#{appId}",
"X-LC-Key": "#{appKey}",
"Content-Type": "application/json"
},
}).then(async res => {
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`)
const data = await res.json()
const init = () =>
initializeCommentBarrage(data.results
.filter(item => item.url === window.location.pathname)
.map(item => ({
content: item.comment,
nick: item.nick,
mailMd5: md5(item.mail),
id: item.objectId
})))
if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
if (typeof initializeCommentBarrage === "undefined") await utils.getScript('!{url_for(theme.cdn.commentBarrage)}').then(init)
else init()
}).catch(error => console.error("An error occurred while fetching comments: ", error))
}
@@ -0,0 +1,67 @@
- const { envId, option ,pageview } = theme.waline
- const { lazyload, count, commentBarrage,use } = theme.comment
script.
(() => {
let walineInitFunction = window.walineFn || null
function initWaline(initFn) {
const walineOptions = {
el: '#waline-wrap',
serverURL: '!{envId}',
pageview: !{pageview},
dark: 'html[data-theme="dark"]',
path: window.location.pathname,
comment: !{count},
...!{JSON.stringify(option)}
}
const walineInstance = initFn(walineOptions)
utils.addGlobalFn('pjax', () => walineInstance.destroy(), 'destroyWaline')
GLOBAL_CONFIG.lightbox && utils.lightbox(document.querySelectorAll('#comment .wl-content img:not(.wl-emoji)'))
sco.owoBig({
body: '.wl-emoji-popup',
item: '.wl-tab-wrapper button'
})
}
async function loadWaline() {
if (walineInitFunction) initWaline(walineInitFunction)
else {
await utils.getCSS('!{url_for(theme.cdn.waline_css)}')
const {init} = await import('!{url_for(theme.cdn.waline_js)}')
walineInitFunction = init || Waline.init
initWaline(walineInitFunction)
window.walineFn = walineInitFunction
}
!{commentBarrage} && barrageWaline()
}
if (!{use[0] === 'Waline'} || !{lazyload}) {
if (!{lazyload}) utils.loadComment(document.getElementById('waline-wrap'), loadWaline)
else loadWaline()
} else window.loadTwoComment = loadWaline
})()
if commentBarrage
script.
async function barrageWaline() {
const url = new URL('!{envId}/api/comment')
const params = {path: window.location.pathname, sortBy: 'insertedAt_asc'}
Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value))
await fetch(url).then(async res => {
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`)
const data = await res.json();
const regex = /<img [^>]*class="wl-emoji"[^>]*>/;
const init = () => {
initializeCommentBarrage(data.data.data
.map(item => ({
nick: item.nick,
mailId: item.avatar,
content: item.comment.replace(regex, ''),
id: item.objectId
})))
}
if (typeof initializeCommentBarrage === "undefined") await utils.getScript('!{url_for(theme.cdn.commentBarrage)}').then(init)
else init()
}).catch(error => console.error("An error occurred while fetching comments: ", error))
}
@@ -0,0 +1,3 @@
div.needEndHide#nav-music(onclick="sco.musicToggle()")
div#nav-music-hoverTips=__('music.hit')
meting-js(id=theme.capsule.id, server=theme.capsule.server, type="playlist", mutex="true", preload="none", data-lrctype="0", order="random", theme="var(--efu-main)")
@@ -0,0 +1,92 @@
- const { server, site, option } = theme.artalk
- const avatarCdn = theme.comment.avatar
script(pjax).
(() => {
const changeContent = content => {
if (content === '') return content;
const replacements = [
{
regex: /<img.*?src="(.*?)"?[^\>]+>/ig,
replacement: '[!{_p("console.newest_comment.image")}]'
},
{
regex: /<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi,
replacement: '[!{_p("console.newest_comment.link")}]'
},
{
regex: /<pre><code>.*?<\/pre>/gi,
replacement: '[!{_p("console.newest_comment.code")}]'
},
{
regex: /<[^>]+>/g,
replacement: ''
}
];
content = replacements.reduce((str, {regex, replacement}) => str.replace(regex, replacement), content);
return content.length > 150 ? content.substring(0, 100) + '...' : content;
};
const generateHtml = (array, asideList) => {
asideList.innerHTML = array.length ? array.map(item => `
<div class='aside-list-item'>
<div class='thumbnail'>
<img src='${item.avatar}' alt='${item.nick}'>
</div>
<div class='content'>
<div class='comment' onclick='pjax.loadUrl("${item.url}")'>${item.content}</div>
<time class="datetime" datetime="${item.date}"></time>
</div>
</div>
`).join('') : "!{_p('newest_comment.zero')}";
window.lazyLoadInstance?.update();
window.pjax?.refresh();
sco?.changeTimeFormat(document.querySelectorAll('.aside-list-item time'));
};
const getSetting = async () => {
try {
const res = await fetch('!{server}/api/v2/conf', {method: 'GET'});
return await res.json();
} catch (e) {
console.error(e);
return null;
}
};
const getComment = async (asideList) => {
const searchParams = new URLSearchParams({'site_name': "!{site}", 'limit': '6'});
await fetch(`!{server}/api/v2/stats/latest_comments?${searchParams}`, {method: 'GET'}).then(async res => {
const result = await res.json();
const avatarConfig = await getSetting();
const avatarCdn = '!{avatarCdn}' + '/avatar/';
const params = avatarConfig?.gravatar?.params || '';
const artalk = result.data.map(e => ({
avatar: avatarCdn + e.email_encrypted + '?' + params,
content: changeContent(e.content_marked),
nick: e.nick,
url: e.page_key + `#atk-comment-${e.id}`,
date: e.date,
})).slice(0, !{limit});
utils.saveToLocal.set('artalk-newest-comments', artalk, !{theme.comment.newest_comment.storage});
generateHtml(artalk, asideList);
}).catch(error => {
console.error(error);
asideList.textContent = "!{_p('newest_comment.error')}";
});
};
const newestCommentInit = (asideList) => {
if (!asideList) return;
const data = utils.saveToLocal.get('artalk-newest-comments');
if (data) {
generateHtml(data, asideList);
} else {
getComment(asideList);
}
};
const $asideList = document.querySelector('.card-recent-comment .aside-list');
window.addEventListener('DOMContentLoaded', () => newestCommentInit($asideList), false)
window.addEventListener('pjax:complete', () => newestCommentInit(document.querySelector('.card-recent-comment .aside-list')), false);
})();
@@ -0,0 +1,11 @@
- var limit = theme.aside.newest_comment.limit ? theme.aside.newest_comment.limit : 5
if theme.comment.use
case theme.comment.use[0]
when 'Twikoo'
!=partial('includes/widgets/third-party/news-comment/twikoo', {limit}, {cache: true})
when 'Waline'
!=partial('includes/widgets/third-party/news-comment/waline', {limit}, {cache: true})
when 'Valine'
!=partial('includes/widgets/third-party/news-comment/valine', {limit}, {cache: true})
when 'Artalk'
!=partial('includes/widgets/third-party/news-comment/artalk', {limit}, {cache: true})
@@ -0,0 +1,69 @@
script.
(() => {
const changeContent = (content) => {
if (!content) return '';
const replacements = [
{regex: /<img.*?src="(.*?)"?[^\>]+>/ig, replacement: '[!{_p("console.newest_comment.image")}]'},
{
regex: /<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi,
replacement: '[!{_p("console.newest_comment.link")}]'
},
{regex: /<pre><code>.*?<\/pre>/gi, replacement: '[!{_p("console.newest_comment.code")}]'},
{regex: /<[^>]+>/g, replacement: ''}
]
content = replacements.reduce((str, {regex, replacement}) => str.replace(regex, replacement), content)
return content.length > 150 ? `${content.substring(0, 100)}...` : content
}
const generateHtml = (array) => {
const html = array.map(item => `
<div class='aside-list-item'>
<div class='thumbnail'>
<img src='${item.avatar}' alt='${item.nick}'>
</div>
<div class='content'>
<div class='comment' onclick='pjax.loadUrl("${item.url}")'>${item.content}</div>
<time class="datetime" datetime="${item.date}"></time>
</div>
</div>
`).join('')
document.querySelector('.card-recent-comment .aside-list').innerHTML = array.length ? html : "!{_p('newest_comment.zero')}"
window.lazyLoadInstance?.update()
window.pjax?.refresh()
sco?.changeTimeFormat(document.querySelectorAll('.aside-list-item time'))
}
const getComment = async () => {
const runTwikoo = () => {
twikoo.getRecentComments({
envId: '!{theme.twikoo.envId}',
region: '',
pageSize: !{limit},
includeReply: true
}).then(res => {
const twikooArray = res.map(e => ({
content: changeContent(e.comment),
avatar: e.avatar,
nick: e.nick,
url: `${e.url}#${e.id}`,
date: new Date(e.created).toString()
})).slice(0, 6)
utils.saveToLocal.set('twikoo-newest-comment', twikooArray, !{theme.comment.newest_comment.storage})
generateHtml(twikooArray)
}).catch((err) => {
console.error(err);
document.querySelector('.card-recent-comment .aside-list').textContent = "!{_p('newest_comment.error')}"
})
}
if (typeof twikoo === 'object') {
runTwikoo()
} else {
utils.getScript('!{url_for(theme.cdn.twikoo)}').then(runTwikoo)
}
}
const newestCommentInit = () => {
if (!document.querySelector('.card-recent-comment')) return
const data = utils.saveToLocal.get('twikoo-newest-comment')
data ? generateHtml(data) : getComment()
}
window.addEventListener('DOMContentLoaded', newestCommentInit, false)
window.addEventListener('pjax:complete', newestCommentInit, false);
})()
@@ -0,0 +1,85 @@
script.
(() => {
const emojiReg = /:[a-z0-9_\u4e00-\u9fa5]+:/g
const changeContent = (content) => {
if (content === '') return content;
const replacements = [
{regex: /<img.*?src="(.*?)"?[^\>]+>/ig, replacement: '[!{_p("console.newest_comment.image")}]'},
{
regex: /<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi,
replacement: '[!{_p("console.newest_comment.link")}]'
},
{regex: /```[\s\S]*?```/g, replacement: '[!{_p("console.newest_comment.code")}]'},
{regex: /<[^>]+>/g, replacement: ""}
];
content = replacements.reduce((str, {regex, replacement}) => str.replace(regex, replacement), content);
return content.length > 150 ? content.substring(0, 100) + '...' : content;
}
const $asideList = document.querySelector('.card-recent-comment .aside-list')
const newestCommentInit = () => {
if (!document.querySelector('.card-recent-comment')) return
const data = utils.saveToLocal.get('valine-newest-comment')
if (data) {
generateHtml(data)
} else {
getComment()
}
}
const getComment = async () => {
const settings = {
"method": "GET",
"headers": {
"X-LC-Id": '!{theme.valine.appId}',
"X-LC-Key": '!{theme.valine.appKey}',
"Content-Type": "application/json"
},
}
if (typeof md5 === "undefined") await utils.getScript('!{url_for(theme.cdn.blueimp_md5)}')
await fetch('!{theme.valine.serverURLs}/1.1/classes/Comment?limit=8&order=-createdAt', settings).then(res => res.json())
.then(async result => {
let ls = []
for (const i of result.results.slice(0, !{limit})) {
if (emojiReg.test(i.comment)) continue
ls.push({
content: changeContent(i.comment),
avatar: '!{theme.comment.avatar}' + '/avatar/' + md5(i.mail.toLowerCase()),
nick: i.nick,
url: i.url,
date: i.updatedAt || i.createdAt
})
}
utils.saveToLocal.set('valine-newest-comment', ls, !{theme.comment.newest_comment.storage})
generateHtml(ls)
}).catch(error => {
console.error(error);
$asideList.textContent = "!{_p('newest_comment.error')}"
})
}
const generateHtml = array => {
const $dom = document.querySelector('.card-recent-comment .aside-list')
$dom.innerHTML = array.length ? array.map(item => `
<div class='aside-list-item'>
<div onclick='pjax.loadUrl(\"${item.url}\")' class='thumbnail'>
<img src='${item.avatar}' alt='${item.nick}'>
<div class='name'><span>${item.nick}</span></div>
</div>
<div class='content'>
<div class='comment' onclick='pjax.loadUrl("${item.url}")'>${item.content}</div>
<time class="datetime" datetime="${item.date}"></time>
</div>
</div>
`).join('') : "!{_p('newest_comment.zero')}"
window.lazyLoadInstance?.update()
window.pjax?.refresh()
sco?.changeTimeFormat(document.querySelectorAll('.aside-list-item time'))
}
window.addEventListener('DOMContentLoaded', newestCommentInit, false)
window.addEventListener('pjax:complete', newestCommentInit, false);
})()
@@ -0,0 +1,73 @@
script.
(() => {
const changeContent = (content) => {
if (content === '') return content;
const replacements = [
{regex: /<img.*?src="(.*?)"?[^\>]+>/ig, replacement: '[!{_p("console.newest_comment.image")}]'},
{
regex: /<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi,
replacement: '[!{_p("console.newest_comment.link")}]'
},
{regex: /<pre><code>.*?<\/pre>/gi, replacement: '[!{_p("console.newest_comment.code")}]'},
{regex: /<[^>]+>/g, replacement: ""}
];
content = replacements.reduce((str, {regex, replacement}) => str.replace(regex, replacement), content);
return content.length > 150 ? content.substring(0, 100) + '...' : content;
}
const $asideList = document.querySelector('.card-recent-comment .aside-list')
const newestCommentInit = () => {
if (!document.querySelector('.card-recent-comment')) return
const data = utils.saveToLocal.get('waline-newest-comment')
if (data) {
generateHtml(data)
} else {
getComment()
}
}
const getComment = async () => {
await fetch('!{theme.waline.envId}/api/comment?type=recent&count=!{limit}', {method: 'GET'}).then(async res => {
const result = await res.json()
const walineArray = result.data.map(e => {
return {
'content': changeContent(e.comment),
'avatar': e.avatar,
'nick': e.nick,
'url': e.url + '#' + e.objectId,
'date': new Date(e.time || e.insertedAt)
}
})
utils.saveToLocal.set('waline-newest-comment', walineArray, !{theme.comment.newest_comment.storage})
generateHtml(walineArray)
}).catch(error => {
console.error(error)
$asideList.textContent = "!{_p('newest_comment.error')}"
})
}
const generateHtml = array => {
const $dom = document.querySelector('.card-recent-comment .aside-list')
$dom.innerHTML = array.length ? array.map(item => `
<div class='aside-list-item'>
<div onclick='pjax.loadUrl("${item.url}")' class='thumbnail'>
<img src='${item.avatar}' alt='${item.nick}'>
<div class='name'><span>${item.nick}</span></div>
</div>
<div class='content'>
<div class='comment' onclick='pjax.loadUrl("${item.url}")'>${item.content}</div>
<time class="datetime" datetime="${item.date}"></time>
</div>
</div>
`).join('') : "!{_p('newest_comment.zero')}"
window.lazyLoadInstance?.update()
window.pjax?.refresh()
sco?.changeTimeFormat(document.querySelectorAll('.aside-list-item time'))
}
window.addEventListener('DOMContentLoaded', newestCommentInit, false)
window.addEventListener('pjax:complete', newestCommentInit, false);
})()
@@ -0,0 +1,39 @@
- const google_adsense = theme.google_adsense.enable
script.
const pjax = new Pjax({
elements: 'a:not([target="_blank"])',
selectors: ['title','#body-wrap','#site-config','meta[name="description"]','.js-pjax','meta[property^="og:"]','#config-diff'],
cacheBust: false,
analytics: !{google_adsense},
scrollRestoration: false
})
document.querySelectorAll('script[data-pjax]').forEach(item => {
const newScript = document.createElement('script')
const content = item.text || item.textContent || item.innerHTML || ""
Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
newScript.appendChild(document.createTextNode(content))
item.parentNode.replaceChild(newScript, item)
})
document.addEventListener('pjax:complete', () => {
window.refreshFn()
document.querySelectorAll('script[data-pjax]').forEach(item => {
const newScript = document.createElement('script')
const content = item.text || item.textContent || item.innerHTML || ""
Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
newScript.appendChild(document.createTextNode(content))
item.parentNode.replaceChild(newScript, item)
})
GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update()
})
document.addEventListener('pjax:error', (e) => {
if (e.request.status === 404) {
pjax.loadUrl('/404.html')
}
})
@@ -0,0 +1,20 @@
#algolia-search
.search-dialog
.algolia-navbar
.search-dialog__title#algolia-search-title=__('nav.search')
.algolia-tips
i.solitude.st-algolia-fill
span.algolia-tips-text='Algolia'
span.search-close-button
i.solitude.st-close-fill
#algolia-input-panel
#algolia-search-input
#search-results
#algolia-hits
each tag in theme.search.tags || []
a.tag-list(href='javascript:void(0);' onclick="pjax.loadUrl('" + url_for('/tags/' + tag) + "/')")=tag
#algolia-tips
#algolia-pagination
#algolia-stats
#search-mask
@@ -0,0 +1,8 @@
if theme.search.enable
case theme.search.type
when 'algolia'
include algolia-search
script(src=url_for(theme.cdn.algolia_js))
when 'local'
include local-search
script(src=url_for(theme.cdn.local_search))
@@ -0,0 +1,16 @@
#local-search
div.search-dialog
nav.search-nav
span.search-dialog-title=__('nav.search')
button.search-close-button
i.solitude.st-close-fill
div.search-wrap
div.search-box
input.search-box-input#search-input(type="text", autocomplete="off", spellcheck="false", autocorrect="off", autocapitalize="off", placeholder=__('search.placeholder'))
div#search-results
#search-hits
each tag in theme.search.tags || []
a.tag-list(href='javascript:void(0);' onclick="pjax.loadUrl('" + url_for('/tags/' + tag) + "/')")=tag
div#search-pagination
div#search-tips
div#search-mask
@@ -0,0 +1,26 @@
- const {key,option,title} = theme.tianli_talk
span.needEndHide#efuTalk(onclick="togglePostChatContainer(); return false;" title=title)
i.solitude.st-robot-fill
span.efuTalkTitle=title
script.
var postChatConfig = {
backgroundColor: "var(--efu-main)",
bottom: "60px",
...!{JSON.stringify(option)}
};
let b = true;
document.getElementById('efuTalk').addEventListener('click', function () {
this.classList.toggle('on');
let efu = this
b && setTimeout(() => {
document.getElementById('close-button').addEventListener('click', function () {
efu.classList.remove('on');
})
}, 0);
b = false
});
script(pjax data-postChat_key=key src="https://ai.tianli0.top/static/public/postChatUser.min.js")