子比主题添加朋友圈和收藏栏

子比主题添加朋友圈和收藏栏

概述

原版教程:https://gavin-chen.top/post/602922a7.html

适配友链朋友圈收藏栏,让wordpress朋友圈有收藏功能

图片[1]-子比主题添加朋友圈和收藏栏-瀚星阁

详细效果请前往 朋友圈 页面查看。

关于收藏栏的后端部分,这里采用的是Github+Supabase+Vercel的方案,另外配有缓存机制,首次进入页面调用云端数据库的数据,重新进入页面则调用本地缓存,缓存设有 1 天的有效期,过期后会自动拉取云端数据库以更新本地缓存。另外为实现多端同步,在收藏栏右上角设有刷新按钮,可以实现一键同步。收藏栏默认显示两行,多余部分折叠隐藏,可点击右上角按钮展开全部内容。

朋友圈配置

这个文章收藏是在友链朋友圈的基础上延伸出来的一个附加功能,所以基础是要先配置好友链朋友圈功能。朋友圈我是按照 官方文档 配置的,其中后端部分采用的是Github+Sqlite+Vercel的 无服务器部署 方式,前端部分采用的是 林木木 的方案。林木木的方案不带管理面板,如果需要更改设置的话,会比较麻烦,但优点是代码量少,简短易读,方便我二次修改。

林木木的朋友圈方案配有一个顶栏,可以显示“订阅”、“活跃”、“日志”等消息,点击“订阅”可以查看随机一个友链的文章列表,点击“活跃”可以切换私有友链库和公共库两种数据源,点击“日志”可以手动清空本地缓存,重新拉取云端数据库。另外支持“创建日期”和“更新日期”两种排列方式,可以自由手动切换。

数据库配置

Vercel 的 Integrations Marketplace 上提供有很多种数据库,其中 MongoDB Atlas 之前在部署 twikoo 评论的时候用过,Upstash 在配置个人网盘的时候用过,听群友推荐说 PlanetScale 和 Supabase 也不错。这里采用 Supabase 作为项目云端数据存储。

图片[2]-子比主题添加朋友圈和收藏栏-瀚星阁

注册 Supabase 后进入 Dashboard,首先点击 New project 创建一个新的项目,设置项目名称和数据库密码,选择合适的地区,然后确认创建。整个创建过程有点长,需要耐心等待几十秒的时间。

图片[3]-子比主题添加朋友圈和收藏栏-瀚星阁

创建完成会自动进入项目,页面左侧有一条纵向菜单栏,点击 Table Editor 可以对数据库进行可视化操作,点击 SQL Editor 可以进行命令行操作,这对于小白来说还是非常方便的。我们进入 Table Editor 点击 New table 创建一个新数据表(建议数据表名字设置为Subscribe),设置好表名、描述,最重要的是各列的参数配置,默认的 Column 有 id 和 created_at 两列,点击 Add column 新增几条参数,分别是 index、title、link、author、avatar、time 六个参数,参数类型均设置为 text,点击 save 保存。

图片[4]-子比主题添加朋友圈和收藏栏-瀚星阁
图片[5]-子比主题添加朋友圈和收藏栏-瀚星阁

进入数据表,点击 Insert 可以手动插入数据,因为是可视化界面,增删改查都十分直观。当然我们不需要在这里插入数据,而是要能够在外部调用它的增删改查能力。在左侧菜单栏中点击 API Docs 可以查看详细的使用方法,其中,Introduction 栏提供了初始化代码。

import { createClient } from "@supabase/supabase-js";
const supabaseUrl = "https://xxxxxxxxxxxxx.supabase.co";
const supabaseKey = process.env.SUPABASE_KEY;
const supabase = createClient(supabaseUrl, supabaseKey);

这里有两个重要参数supabaseUrl和supabaseKey,需要在设置里面查找。点击左侧菜单栏中的 Project Settings,点击 API 栏,其中 Project URL 即为 supabaseUrl,Project API keys 即为 supabaseKey。

图片[6]-子比主题添加朋友圈和收藏栏-瀚星阁

回到 API Docs,在 Tables and Views 栏找到刚刚新建的表名,进入文档后可以看到详细的增删改查示例代码。

图片[7]-子比主题添加朋友圈和收藏栏-瀚星阁

后端代码

github 新建一个私有仓库,仓库内主要包含 3 个文件,内容如下。

index.js

注意这里 supabaseUrl 做了脱敏处理,要替换成自己的。

// 导入所需包和模块
const express = require("express");
require("dotenv").config(); // 导入 dotenv 并加载 .env 文件
const app = express();
app.use(function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
// 创建 Express 应用程序
app.use(express.json());
const savedKey = process.env.KEY;
// 连接数据库
const { createClient } = require("@supabase/supabase-js");
const supabaseUrl = "https://xxxxxxxxxxxxxxxxx.supabase.co";
const supabaseKey = process.env.SUPABASE_KEY;
const supabase = createClient(supabaseUrl, supabaseKey);
// 新增收藏
app.get("/subscribe", async (req, res) => {
try {
const key = req.query.key.toString();
const index = req.query.index.toString();
const title = req.query.title.toString();
const link = req.query.link.toString();
const author = req.query.author.toString();
const avatar = req.query.avatar.toString();
const time = req.query.time.toString();
if (key == savedKey) {
// 存入数据库
const { data: filterData, error: error1 } = await supabase
.from("Subscribe")
.select()
.eq("index", index);
if (error1) {
console.error("Error:", error1);
res.status(500).json({ code: "500", message: "查询失败", content: "" });
} else {
if (!filterData.length) {
const { data: createdData, error: error2 } = await supabase
.from("Subscribe")
.insert([
{
index: index,
title: title,
link: link,
author: author,
avatar: avatar,
time: time,
},
])
.select();
if (error2) {
console.error("Error:", error2);
res
.status(500)
.json({ code: "500", message: "存储失败", content: "" });
} else {
console.log("Data stored successfully:", createdData[0]);
res.status(200).json({
code: "200",
message: "存储成功",
content: createdData[0],
});
}
} else {
res
.status(402)
.json({ code: "402", message: "文章已存在", content: "" });
}
}
} else {
res.status(401).json({ code: "401", message: "密码错误", content: "" });
}
} catch (error) {
console.error(error);
res.status(500).json({ error: "Internal Server Error" });
}
});
// 文章删除
app.get("/delsavedtitles", async (req, res) => {
try {
const key = req.query.key.toString();
const index = req.query.index.toString();
if (key == savedKey) {
const { data, error } = await supabase
.from("Subscribe")
.delete()
.eq("index", index);
if (error) {
console.error("Error:", error);
res.status(500).json({ code: "500", message: "删除失败", content: "" });
} else {
if (!data.length) {
res
.status(404)
.json({ code: "404", message: "未找到文章", content: data });
} else {
console.log("Data delete completely");
res
.status(200)
.json({ code: "200", message: "删除成功", content: data });
}
}
} else {
res.status(401).json({ code: "401", message: "密码错误", content: "" });
}
} catch (error) {
console.error(error);
res.status(500).json({ error: "Internal Server Error" });
}
});
// 收藏文章查询
app.get("/getsavedtitles", async (req, res) => {
try {
const mode = req.query.mode.toString();
const column = req.query.column.toString();
const value = req.query.value.toString();
if (mode == "search") {
const { data: filterData, error } = await supabase
.from("Subscribe")
.select()
.eq(column, value);
if (error) {
console.error("Error:", error);
res.status(404).json({ code: "404", message: "查询失败", content: "" });
} else {
console.log("Data serach completely:", filterData);
res
.status(200)
.json({ code: "200", message: "查询成功", content: filterData });
}
} else if (mode == "all") {
const { data: filterData, error } = await supabase
.from("Subscribe")
.select();
if (error) {
console.error("Error:", error);
res.status(404).json({ code: "404", message: "查询失败", content: "" });
} else if (mode == "all") {
console.log("Data serach completely:", filterData);
res
.status(200)
.json({ code: "200", message: "查询成功", content: filterData });
}
} else {
res.status(401).json({ code: "401", message: "参数错误", content: "" });
}
} catch (error) {
console.error(error);
res.status(500).json({ error: "Internal Server Error" });
}
});
// 启动服务器
const server = app.listen(process.env.PORT || 3000, () => {
const port = server.address().port;
console.log(`Server is running on port ${port}`);
});

package.json

{
"name": "projectname",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "Echo \"error: error\" && exit 1",
"start": "node index.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"axios": "^0.27.2",
"express": "^4.18.1",
"dotenv": "^8.2.0",
"@supabase/supabase-js": "^1.0.0"
}
}

vercel.json

注意 KEY 和 SUPABASE_KEY 要换成自己的,其中KEY为 SHA256 加密后的前端身份验证密码,SUPABASE_KEY为 Supabase 密钥

{
"version": 2,
"builds": [
{
"src": "./index.js",
"use": "@vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/"
}
],
"env": {
"KEY": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"SUPABASE_KEY": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}

仓库建好后,部署到 Vercel 上,在 Storage 栏进入 Integrations Marketplace 找到 Supabase,点击 Add Integration 将其添加进项目。然后就是配置自定义域名,自此后端配置完成。

如果vercel添加supabase storage出现错误,导致无法正常使用那么可以开启RLS功能

图片[8]-子比主题添加朋友圈和收藏栏-瀚星阁
图片[9]-子比主题添加朋友圈和收藏栏-瀚星阁

前端代码

moments.php

原版教程的是html代码,但是在wordpress的页面上添加html代码,无法跟效果图一样

<?php
/**
* Template name: 安凝雪科技-朋友圈
* Description:   安凝雪科技-朋友圈
*/
get_header();
$header_style = zib_get_page_header_style();
?>
<style>
.container {
max-width: var(--mian-max-width);
width: 1200px!important;
}
#head-cover {
width: 1200px;
height: 350px;
margin: 0 0 20px;
border: 1px solid var(--gavin-border-color);
box-shadow: var(--gavin-shadow-2);
max-width: var(--mian-max-width);
left:120px;
border-radius: 20px;
overflow: hidden;
position: relative;
}
.head-cover-descr {
position: absolute;
bottom: 40px;
left: 40px;
line-height: 1.3;
font-size: 1.15rem;
color: #f5f5f5;
text-shadow: 0 0 2px rgba(0,0,0,.5);
max-width: calc(100% - 50px);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
z-index: 1;
}
.head-cover-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.head-cover-title {
position: absolute;
top: 40px;
left: 40px;
color: #fff;
font-size: 2.5rem;
font-weight: 700;
line-height: 1;
text-shadow: 0 0 10px rgba(0,0,0,.5);
z-index: 1;
}
#head-cover, header a, header img, header nav, header span, header time {
user-select: none;
}
</style>
<div id="head-cover"><img class="head-cover-img entered loaded" src="https://i3.wp.com/file.77il.cn/wp-content/uploads/2023/04/88a992dcfe211559.jpg" data-lazy-src="https://i3.wp.com/file.77il.cn/wp-content/uploads/2023/04/88a992dcfe211559.jpg" alt="cover" data-ll-status="loaded"><span class="head-cover-title">订阅</span><span class="head-cover-descr">使用 友链朋友圈 订阅友链最新文章</span></div>
<main class="container"></div>
<h2 id="我的收藏">
我的收藏
<a class="refresh" onclick="localStorage.removeItem('savedArticles');location.reload();">
<i class="blogfont icon-refresh"></i>
</a>
<a class="fold" onclick="foldSavedArticles(event)">
<i class="blogfont icon-arrow-down"></i>
</a>
</h2>
<div id="cf-saved-post">
</div>
<h2 id="最新文章">
最新文章
</h2>
<div class="post-content">
<div id="cf-container">
与主机通讯中……
</div>
</div>
<div class="inputBoxMain" id="fcircleInputBox">
<div class="inputBox">
<div class="content-body">
<span class="title"></span>
<span class="tips">请输入密码以验证您的身份</span>
<input class="input-password" type="password" placeholder="密码">
</div>
<div class="content-bottom">
<span class="btn close" onclick="switchSecretInput()">取消</span>
<span class="btn" onclick="sendSubscribeInfo()">确认</span>
</div>
</div>
<div class="noteBox hide">
<a class="icon">
<i class="fas fa-spinner fa-spin"></i>
</a>
<span class="tips">请稍候 ...</span>
</div>
<div class="inputBoxMask">
</div>
</div>
<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/crypto-js/4.1.1/crypto-js.min.js"></script>
<link rel="stylesheet" href="/anxkj/css/link.css">
<link rel="stylesheet" href="https://npm.elemecdn.com/element-ui@2.15.6/lib/theme-chalk/index.css"  media="defer" onload="this.media='all'">
<script async src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js"></script>
<script async src="https://npm.elemecdn.com/element-ui@2.15.6/lib/index.js"></script>
<body>
<script src="/anxkj/js/moments.js"></script>
<script src="/anxkj/js/sc.js"></script>
</body>
<?php the_content( $more_link_text, $strip_teaser, $more_file ); ?>
<?php comments_template('/template/comments.php', true); ?>
</div>
</main>
<?php
get_footer();

link.css

这里使用得是铭心石刻的css,这边调整了一部分代码(颜色代码的失效)

:root {
--kouseki-floorcolor: #a9a9b3;
--kouseki-dark-floorcolor: #454545
}[data-theme=light] {
--kouseki-bg-3: rgb(248,248,248)
}[data-theme=dark] {
--kouseki-bg-3: rgb(7,7,7)
}
#article-container a:not([data-fancybox=gallery]):not(.headerlink):not(.cf-friends-link):not(.tag-Link):not(.btn-anzhiyu):not(.no-text-decoration) {
border-bottom: none;
font-family: zzht
}
#article-container a:not([data-fancybox=gallery]):not(.headerlink):not(.cf-friends-link):not(.btn-anzhiyu):not(.no-text-decoration):hover {
background: 0 0;
color: var(--anzhiyu-main)
}
#cf-state {
font-size: 16px;
border-radius: .8rem;
border: 1px solid var(--kouseki-card-border);
box-shadow: none;
margin: 0 0 20px;
overflow: hidden;
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 8px 0
}
.cf-state-data {
width: 100%;
display: flex;
justify-content: space-evenly;
margin-top: 10px
}
.cf-data-active,.cf-data-article,.cf-data-friends {
height: 60px;
background: 0 0;
display: flex;
flex-direction: column;
cursor: pointer;
font-weight: 700
}
.cf-data-active:hover,.cf-data-article:hover,.cf-data-friends:hover {
color: var(--kouseki-lighttext)
}
.cf-label {
font-size: 16px;
padding: 0;
align-self: center;
text-align: center;
width: 100%;
height: 30px
}
.cf-message {
align-self: center;
text-align: center;
padding: 0;
width: 100%;
font-size: 20px
}
#cf-change {
font-size: 14px;
display: block;
padding: 12px 0 4px;
width: 100%;
text-align: center
}
#cf-more {
width: 60%;
height: 30px;
margin: 20px auto 0;
border-radius: 50px;
border: 1px solid rgb(227, 232, 240);
font-weight: bolder;
text-align: center;
display: flex;
flex-direction: column;
justify-content: space-around;
cursor: pointer;
transition: .3s
}
#cf-more:hover {
width: 100%;
background: var(--kouseki-lighttext);
color: var(--f-0)
}
#cf-more i.fas::before {
content: "∞"
}
#cf-container {
width: 100%;
height: auto;
margin: auto;
display: flex;
flex-wrap: wrap;
gap: 20px
}
#cf-container a {
text-decoration: none
}
.cf-article {
border-radius: .8rem;
border: 1px solid rgb(227, 232, 240);
font-weight: bolder;
overflow: hidden;
transition: all ease-out .3s;
position: relative;
padding: .5rem 1rem;
width: calc(100% / 3 - 40px / 3);
float: left;
height: 110px
}
#cf-container>.cf-article:hover {
transition: all .3s;
-webkit-transform: scale(1.03);
transform: scale(1.03);
border-color: var(--kouseki-lighttext)
}
.cf-article:hover {
border-color: var(--kouseki-lighttext)
}
.cf-article::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 200%;
background: linear-gradient(to right,transparent,#fff,transparent);
transform: translateX(-200%);
transition: transform .5s linear;
z-index: 1
}
.cf-article:hover::before {
transform: translateX(100%) skewX(-60deg)
}
.cf-article-avatar {
display: flex;
align-items: center;
position: absolute;
bottom: 8px;
left: 15px
}
.cf-img-avatar {
align-self: center;
text-align: center;
display: inline-block!important;
width: 22px;
height: 22px;
border-radius: 50%!important;
margin: 0 0 -4px!important;
background: #fff
}
.cf-article-author {
line-height: 35px;
font-size: 14px;
font-weight: 400;
margin-left: 5px;
align-self: center;
text-align: center;
height: 40px;
white-space: nowrap;
overflow: hidden
}
.cf-article-title {
color: var(--kouseki-fontcolor)!important;
font-weight: 500;
position: relative;
z-index: 2;
width: fit-content;
max-width: calc(100% - 30px);
display: -webkit-box;
font-size: 18px;
align-self: start;
text-align: left;
line-height: 1.3;
padding: 0;
margin: 5px 0;
transition: .3s;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2
}
.cf-article-time {
font-size: 14px;
text-align: right;
float: right;
font-weight: 400;
position: absolute;
right: 17px;
bottom: 17px;
line-height: 1
}
.cf-time-created,.cf-time-updated {
display: inline-block;
text-align: left;
white-space: nowrap
}
.cf-time-created i.far,.cf-time-updated i.fas {
padding-right: 8px
}
.cf-article-time i:before {
margin-right: 5px
}
#cf-footer {
margin: 6rem 1% 2rem 0;
text-align: right;
font-size: 13px;
color: var(--kouseki-note-font-color)
}
.cf-data-lastupdated {
font-size: 13px;
text-align: right;
display: block
}
#cf-overlay,#cf-overshow {
position: fixed;
width: 100%;
height: 100%
}
#cf-overlay {
top: 0;
left: 0;
background-color: rgba(255,255,255,.12);
-webkit-backdrop-filter: blur(0);
backdrop-filter: blur(0);
overflow-y: auto;
pointer-events: none;
opacity: 0;
transition: all .5s ease;
z-index: 998
}
#cf-overshow {
bottom: 0;
left: 0;
opacity: 0;
pointer-events: none;
transition: all .5s ease;
z-index: 999
}
#cf-overlay.cf-show-now {
left: 0;
-webkit-backdrop-filter: blur(7px);
backdrop-filter: blur(7px);
opacity: 1;
transition: all .5s ease
}
#cf-overshow.cf-show-now {
bottom: 0;
opacity: 1;
pointer-events: all;
transition: all .5s ease
}
.cf-overshow {
text-align: center;
border-radius: 1rem;
position: absolute;
width: 290px;
padding: 0 10px;
min-height: 170px;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
box-shadow: 0 12px 40px rgba(0,0,0,.093);
background: var(--kouseki-card-bg-about);
border: 1px solid var(--kouseki-border-color)
}
.cf-overshow-head:hover img.cf-img-avatar {
transform: rotate(360deg);
transition: .8s
}
.cf-overshow .cf-overshow-head a {
color: var(--dis-f-0)!important;
display: block;
text-align: center;
font-weight: 700;
margin-top: -5px;
padding: 5px 8px 5px
}
.cf-overshow img.cf-img-avatar {
background: #fff;
width: 80px;
height: 80px;
border-radius: 50%!important;
margin: 20px auto 0!important;
box-shadow: 0 12px 40px rgb(0 0 0 / 9%);
transform: rotate(-360deg);
transition: .3s!important
}
.cf-overshow p {
margin: .3rem 5px;
width: 100%;
position: relative
}
.cf-overshow p a.cf-article-title {
display: block;
text-align: left;
position: relative;
z-index: 2;
font-size: 15px;
font-weight: 600;
line-height: 25px;
margin-bottom: 15px;
letter-spacing: normal;
max-height: 50px;
overflow: hidden;
white-space: normal;
text-overflow: ellipsis;
display: -webkit-box;
display: box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical
}
.cf-overshow p span {
position: absolute;
bottom: -1rem;
right: 8px;
z-index: 1;
font-style: italic;
font-size: 12px
}
#cf-container .cf-overshow p a:hover {
letter-spacing: 1px;
transition: .3s
}
.cf-overshow .cf-overshow-content {
padding: 10px 10px 25px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px
}
#cf-overshow .cf-overshow-close {
position: sticky;
display: block;
width: 100%;
height: 100%
}
.cf-article .cf-article-title:hover {
color: var(--kouseki-lighttext)!important
}
#cf-more i.fas:hover {
color: #fff;
transition: .5
}
#cf-more,#cf-state {
background: #fff;
color: #363636
}
#cf-change,.cf-article-floor,.cf-time-created,.cf-time-updated {
color: var(--kouseki-floorcolor)
}
.cf-article a.cf-article-title,.cf-article-author,.cf-article:hover .cf-time-created,.cf-article:hover .cf-time-updated {
color: var(--kouseki-fontcolor)
}
.cf-article {
background: #fff;
box-shadow: 0 8px 12px -4px #2c2d300c;
}
#cf-change span:hover {
color: var(--kouseki-lighttext);
cursor: pointer
}
#cf-change .cf-change-now {
color: rgb(129,78,250);
font-weight: 800
}
.cf-overshow p a:hover {
color: var(--kouseki-blue2)!important;
text-decoration: none!important
}
.cf-overshow p span {
color: var(--kouseki-note-font-color)
}
.dark-theme #cf-overlay,.theme-dark #cf-overlay {
background-color: rgba(59,61,66,.42)
}
.dark-theme .cf-overshow,.theme-dark .cf-overshow {
background: #292a2d
}
.dark-theme .cf-overshow p a,.theme-dark .cf-overshow p a {
color: var(--kouseki-fontcolor)
}
.dark-theme .cf-overshow .cf-overshow-content,.theme-dark .cf-overshow .cf-overshow-content {
background: #eaeaea
}
.dark-theme #cf-more,.dark-theme #cf-state,.theme-dark #cf-more,.theme-dark #cf-state {
background: var(--kouseki-card-bg-about);
color: var(--kouseki-dark-fontcolor)
}
.dark-theme #cf-change,.dark-theme .cf-article-floor,.dark-theme .cf-time-created,.dark-theme .cf-time-updated,.theme-dark #cf-change,.theme-dark .cf-article-floor,.theme-dark .cf-time-created,.theme-dark .cf-time-updated {
color: var(--kouseki-dark-floorcolor)
}
.dark-theme .cf-article a.cf-article-title,.dark-theme .cf-article-author,.theme-dark .cf-article a.cf-article-title,.theme-dark .cf-article-author {
color: var(--kouseki-dark-fontcolor)
}
.dark-theme .cf-article,.theme-dark .cf-article {
background: var(--kouseki-card-bg-about)
}
.dark-theme .cf-article:hover .cf-article-floor,.dark-theme .cf-article:hover .cf-time-created,.dark-theme .cf-article:hover .cf-time-updated,.dark-theme .cf-overshow p span,.theme-dark .cf-article:hover .cf-article-floor,.theme-dark .cf-article:hover .cf-time-created,.theme-dark .cf-article:hover .cf-time-updated,.theme-dark .cf-overshow p span {
color: var(--kouseki-dark-fontcolor)
}
#cf-container .img-alt.is-center {
display: none
}
#article-container a:hover {
text-decoration: none
}
span.cf-article-author:hover {
color: var(--kouseki-lighttext)!important
}
div#cf-footer a {
color: var(--dis-f-0)
}
.cf-overshow-head {
margin: 0 10px;
border-bottom: 1px dashed var(--kouseki-note-font-color)
}
div#cf-random-post {
background: var(--kouseki-card-bg-about);
border: 1px solid var(--kouseki-border-color);
border-radius: .8rem;
height: 4rem;
margin: 0 10px;
display: flex;
align-items: center;
padding: 15px;
color: var(--kouseki-fontcolor);
font-size: 1.1rem;
height: fit-content
}
.cf-overshow>.cf-overshow-content>p {
margin: 0 0 2rem!important
}
.cf-overshow .cf-overshow-head a:hover {
text-decoration: none!important;
color: var(--kouseki-blue2)!important
}
#cf-footer a:hover {
text-decoration: none;
color: var(--kouseki-blue2)
}
.cf-star {
color: var(--kouseki-fontcolor)!important;
width: 35px;
height: 35px;
font-size: 18px;
position: absolute;
right: 8px;
top: 8px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer
}
.cf-star:hover {
color: var(--kouseki-lighttext)!important
}
.cf-star.saved i {
font-weight: 900;
color: orange
}
#fcircleInputBox {
display: flex;
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
z-index: 999;
justify-content: center;
transition: .5s ease;
flex-direction: column;
align-items: center;
pointer-events: none
}
#fcircleInputBox.open {
pointer-events: all
}
#fcircleInputBox.open .inputBox.hide,.inputBox {
width: 300px;
height: 200px;
background: rgb(248,248,248);
border: 1px solid rgb(227, 232, 240);
border-radius: 18px;
overflow: hidden;
position: absolute;
opacity: 0;
pointer-events: none;
transition: .5s ease
}
#fcircleInputBox.open .inputBox {
opacity: 1;
pointer-events: all;
transition: .5s ease
}
.content-body {
width: 100%;
height: 145px;
padding: 20px;
position: relative
}
.content-body span.title {
display: block;
width: 100%;
font-size: 2rem;
font-weight: 700;
line-height: 1.3;
text-align: center;
margin: 0 0 8px
}
.content-body span.tips {
display: block;
width: 100%;
font-size: 1.2rem;
line-height: 1.3;
text-align: center;
color: rgb(102, 102, 102)
}
.content-body input.input-password {
display: block;
line-height: 1.3;
width: 260px;
border-radius: 6px;
height: 35px;
position: absolute;
bottom: 10px;
left: 20px;
padding: 4px 8px;
color: var(--font-color);
background: var(--f-0);
border: 1px solid var(--kouseki-border-color)
}
.content-body input.input-password:focus {
outline: 0
}
.content-body input.input-password::placeholder {
color: var(--kouseki-note-font-color)
}
.content-bottom {
width: 100%;
height: 55px;
border-top: 1px solid var(--kouseki-border-color);
display: flex
}
.content-bottom .btn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
letter-spacing: 1px;
font-size: 1.1rem;
color: rgb(0, 136, 255);
cursor: pointer
}
.content-bottom .btn:first-child {
border-right: 1px solid rgb(227, 232, 240)
}
.content-bottom .btn:hover {
background-color: var(--kouseki-op-dis-1)
}
.inputBoxMask {
background: var(--kouseki-console-mask);
-webkit-backdrop-filter: blur(0);
backdrop-filter: blur(0);
width: 100vw;
height: 100vh;
top: 0;
left: 0;
position: absolute;
z-index: -1;
opacity: 0;
transition: .5s ease;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
transform: translateZ(0)
}
#fcircleInputBox.open .inputBoxMask {
-webkit-backdrop-filter: blur(7px);
backdrop-filter: blur(7px);
opacity: 1;
transform: translateZ(0)
}
#fcircleInputBox .noteBox {
width: 150px;
height: 150px;
background: var(--kouseki-bg-3);
border: 1px solid var(--kouseki-border-color);
border-radius: 15px;
overflow: hidden;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
opacity: 1;
pointer-events: none;
transition: .5s ease
}
#fcircleInputBox .noteBox.hide {
opacity: 0;
transition: .5s ease
}
#fcircleInputBox .noteBox .icon {
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 20px;
color: var(--font-color);
font-size: 48px
}
#fcircleInputBox .noteBox .tips {
position: absolute;
bottom: 27px;
line-height: 1.3;
font-size: 1rem;
color: var(--font-color);
text-align: center
}
#cf-saved-post {
display: flex;
flex-wrap: wrap;
gap: 20px;
max-height: 240px;
overflow: hidden;
transition: .3s ease-in-out
}
#我的收藏 {
display: flex;
align-items: center
}
#我的收藏 .fold,#我的收藏 .refresh {
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
width: 36px;
height: 36px;
position: absolute;
cursor: pointer;
color: rgb(45, 45, 45);
border: 1px solid rgb(227, 232, 240);
background-color: #fff;
transition: .3s
}
#我的收藏 .refresh {
right: 48px
}
#我的收藏 .fold {
right: 0
}
#我的收藏 .fold:hover,#我的收藏 .refresh:hover {
background-color: #fff;
transition: .3s
}
#我的收藏 .refresh i {
font-size: 20px
}
#我的收藏 .fold i {
font-size: 12px
}
@media screen and (max-width:1200px) {
.cf-article {
width: calc(100% / 2 - 20px / 2)!important
}
}
@media screen and (max-width:850px) {
.cf-article {
width: 100%!important
}
}
@media screen and (max-width:500px) {
#cf-more {
width: 100%!important
}
}
@media screen and (max-width:300px) {
#cf-state,.cf-article-time {
display: none
}
}

moments.js

/*
Last Modified time : 20220326 15:38 by https://immmmm.com
已适配 FriendCircle 公共库和主库
*/
//默认数据
var fdata = {
jsonurl: "",
apiurl: "",
apipublieurl: "https://moments.anxkj.top/", //默认公共库
initnumber: 24, //首次加载文章数
stepnumber: 12, //更多加载文章数
article_sort: "created", //文章排序 updated or created
error_img: "https://www.anxkj.top/wp-content/uploads/2023/12/1702785694-c4ce86c69b4e15c246cd8eaf35db1c71-150x150.jpg",
};
if ("undefined" != typeof fdataUser)
for (var key in fdataUser)
fdataUser[key] && (fdata[key] = fdataUser[key]);
var article_num = ""
, sortNow = ""
, UrlNow = ""
, friends_num = ""
, container = document.getElementById("cf-container") || document.getElementById("fcircleContainer")
, localSortNow = localStorage.getItem("sortNow")
, localUrlNow = localStorage.getItem("urlNow");
function loadStatistical(sdata) {
article_num = sdata.article_num,
friends_num = sdata.friends_num;
var messageBoard = `\n    <div id="cf-state" class="cf-new-add">\n      <div class="cf-state-data">\n        <div class="cf-data-friends" onclick="openToShow()">\n          <span class="cf-label">订阅</span>\n          <span class="cf-message">${sdata.friends_num}</span>\n        </div>\n        <div class="cf-data-active" onclick="changeEgg()">\n          <span class="cf-label">活跃</span>\n          <span class="cf-message">${sdata.active_num}</span>\n        </div>\n        <div class="cf-data-article" onclick="clearLocal()">\n          <span class="cf-label">日志</span>\n          <span class="cf-message">${sdata.article_num}</span>\n        </div>\n      </div>\n      <div id="cf-change">\n          <span id="cf-change-created" data-sort="created" onclick="changeSort(event)" class="${"created" == sortNow ? "cf-change-now" : ""}">Created</span> | <span id="cf-change-updated" data-sort="updated" onclick="changeSort(event)" class="${"updated" == sortNow ? "cf-change-now" : ""}" >Updated</span>\n      </div>\n    </div>\n    `
, loadMoreBtn = `\n      <div id="cf-more" class="cf-new-add" onclick="loadNextArticle()"><i class="fas fa-angle-double-down"></i></div>\n      <div id="cf-footer" class="cf-new-add">\n       <span id="cf-version-up" onclick="checkVersion()"></span>\n       <span class="cf-data-lastupdated">更新于:${sdata.last_updated_time}</span>\n        Powered by <a target="_blank" href="https://github.com/Rock-Candy-Tea/hexo-circle-of-friends" target="_blank">FriendCircle</a>\n        <br>\n        Designed by <a target="_blank" href="https://immmmm.com" target="_blank">林木木</a>\n        <br>\n        Adapted by <a target="_blank" href="https://gavin-chen.top" target="_blank">南方嘉木</a>\n      </div>\n      <div id="cf-overlay" class="cf-new-add" onclick="closeShow()"></div>\n      <div id="cf-overshow" class="cf-new-add"></div>\n    `;
container && (container.insertAdjacentHTML("beforebegin", messageBoard),
container.insertAdjacentHTML("afterend", loadMoreBtn))
}
function loadArticleItem(datalist, start, end) {
var articleItem = ""
, articleNum = article_num
, endFor = end;
if (end > article_num && (endFor = article_num),
start < article_num) {
for (var i = start; i < endFor; i++) {
var item = datalist[i], id;
articleItem += `\n        <div class="cf-article ${"cf-" + CryptoJS.MD5(item.link).toString()}">\n            <a class="cf-article-title" href="${item.link}" target="_blank" rel="noopener nofollow" data-title="${item.title}">${item.title}</a>\n            <a class="cf-star" onclick="switchSecretInput(event)"><i class="fa fa-star"></i></a>\n            <div class="cf-article-avatar no-lightbox flink-item-icon">\n                <img class="cf-img-avatar avatar" src="${item.avatar}" alt="avatar" onerror="this.src='${fdata.error_img}'; this.onerror = null;">\n                <a onclick="openMeShow(event)" data-link="${item.link}" class="" target="_blank" rel="noopener nofollow" href="javascript:;"><span class="cf-article-author">${item.author}</span></a>\n            </div>\n            <span class="cf-article-time">\n                <span class="cf-time-created" style="${"created" == sortNow ? "" : "display:none"}">${item.created}</span>\n                <span class="cf-time-updated" style="${"updated" == sortNow ? "" : "display:none"}">${item.updated}</span>\n            </span>\n        </div>\n        `
}
container.insertAdjacentHTML("beforeend", articleItem),
null != savedArticlesIndex && checkStared(savedArticlesIndex),
fetchNextArticle()
} else
document.getElementById("cf-more").outerHTML = '<div id="cf-more" class="cf-new-add" onclick="loadNoArticle()"><small>一切皆有尽头!</small></div>'
}
function loadFcircleShow(userinfo, articledata) {
for (var showHtml = `\n        <div class="cf-overshow">\n          <div class="cf-overshow-head">\n            <img class="cf-img-avatar avatar" src="${userinfo.avatar}" alt="avatar" onerror="this.src='${fdata.error_img}'; this.onerror = null;">\n            <a class="" target="_blank" rel="noopener nofollow" href="${userinfo.link}">${userinfo.name}</a>\n          </div>\n          <div class="cf-overshow-content">\n    `, i = 0; i < userinfo.article_num; i++) {
var item = articledata[i];
showHtml += `\n        <p><a class="cf-article-title"  href="${item.link}" target="_blank" rel="noopener nofollow" data-title="${item.title}">${item.title}</a><span>${item.created}</span></p>\n      `
}
showHtml += "</div></div>",
document.getElementById("cf-overshow").insertAdjacentHTML("beforeend", showHtml),
document.getElementById("cf-overshow").className = "cf-show-now"
}
function fetchNextArticle() {
var start = document.querySelectorAll("#cf-container .cf-article").length
, end = start + fdata.stepnumber
, articleNum = article_num;
if (end > articleNum && (end = articleNum),
start < articleNum) {
UrlNow = localStorage.getItem("urlNow");
var fetchUrl = UrlNow + "rule=" + sortNow + "&start=" + start + "&end=" + end;
fetch(fetchUrl).then(res=>res.json()).then(json=>{
var nextArticle = eval(json.article_data);
console.log("已预载?rule=" + sortNow + "&start=" + start + "&end=" + end),
localStorage.setItem("nextArticle", JSON.stringify(nextArticle))
}
)
} else
(start = articleNum) && (document.getElementById("cf-more").outerHTML = '<div id="cf-more" class="cf-new-add" onclick="loadNoArticle()"><small>一切皆有尽头!</small></div>')
}
function loadNextArticle() {
for (var nextArticle = JSON.parse(localStorage.getItem("nextArticle")), articleItem = "", i = 0; i < nextArticle.length; i++) {
var item = nextArticle[i], id;
articleItem += `\n        <div class="cf-article ${"cf-" + CryptoJS.MD5(item.link).toString()}">\n            <a class="cf-article-title" href="${item.link}" target="_blank" rel="noopener nofollow" data-title="${item.title}">${item.title}</a>\n            <a class="cf-star" onclick="switchSecretInput(event)"><i class="fa fa-star"></i></a>\n            <div class="cf-article-avatar no-lightbox flink-item-icon">\n                <img class="cf-img-avatar avatar" src="${item.avatar}" alt="avatar" onerror="this.src='${fdata.error_img}'; this.onerror = null;">\n                <a onclick="openMeShow(event)" data-link="${item.link}" class="" target="_blank" rel="noopener nofollow" href="javascript:;"><span class="cf-article-author">${item.author}</span></a>\n            </div>\n            <span class="cf-article-time">\n                <span class="cf-time-created" style="${"created" == sortNow ? "" : "display:none"}">${item.created}</span>\n                <span class="cf-time-updated" style="${"updated" == sortNow ? "" : "display:none"}">${item.updated}</span>\n            </span>\n        </div>\n        `
}
container.insertAdjacentHTML("beforeend", articleItem),
null != savedArticlesIndex && checkStared(savedArticlesIndex),
fetchNextArticle()
}
function loadNoArticle() {
var articleSortData = sortNow + "ArticleData";
localStorage.removeItem(articleSortData),
localStorage.removeItem("statisticalData"),
document.getElementById("cf-more").remove(),
window.scrollTo(0, document.getElementsByClassName("cf-state").offsetTop)
}
function clearLocal() {
localStorage.removeItem("updatedArticleData"),
localStorage.removeItem("createdArticleData"),
localStorage.removeItem("nextArticle"),
localStorage.removeItem("statisticalData"),
localStorage.removeItem("sortNow"),
localStorage.removeItem("urlNow"),
location.reload()
}
function checkVersion() {
var url = fdata.apiurl + "version";
fetch(url).then(res=>res.json()).then(json=>{
console.log(json);
var nowStatus = json.status
, nowVersion = json.current_version
, newVersion = json.latest_version
, versionID = document.getElementById("cf-version-up");
versionID.innerHTML = 0 == nowStatus ? "当前版本:v" + nowVersion : 1 == nowStatus ? "发现新版本:v" + nowVersion + " ↦ " + newVersion : "网络错误,检测失败!"
}
)
}
function changeEgg() {
if (fdata.jsonurl || fdata.apiurl) {
document.querySelectorAll(".cf-new-add").forEach(el=>el.remove()),
localStorage.removeItem("updatedArticleData"),
localStorage.removeItem("createdArticleData"),
localStorage.removeItem("nextArticle"),
localStorage.removeItem("statisticalData"),
container.innerHTML = "",
UrlNow = localStorage.getItem("urlNow");
var UrlNowPublic = fdata.apipublieurl + "all?";
UrlNow !== UrlNowPublic ? changeUrl = fdata.apipublieurl + "all?" : fdata.jsonurl ? changeUrl = fdata.apipublieurl + "postjson?jsonlink=" + fdata.jsonurl + "&" : fdata.apiurl && (changeUrl = fdata.apiurl + "all?"),
localStorage.setItem("urlNow", changeUrl),
FetchFriendCircle(sortNow, changeUrl)
} else
clearLocal()
}
function FetchFriendCircle(sortNow, changeUrl) {
var end = fdata.initnumber
, fetchUrl = UrlNow + "rule=" + sortNow + "&start=0&end=" + end;
changeUrl && (fetchUrl = changeUrl + "rule=" + sortNow + "&start=0&end=" + end),
fetch(fetchUrl).then(res=>res.json()).then(json=>{
var statisticalData = json.statistical_data
, articleData = eval(json.article_data)
, articleSortData = sortNow + "ArticleData";
loadStatistical(statisticalData),
loadArticleItem(articleData, 0, end),
localStorage.setItem("statisticalData", JSON.stringify(statisticalData)),
localStorage.setItem(articleSortData, JSON.stringify(articleData))
}
)
}
function changeSort(event) {
sortNow = event.currentTarget.dataset.sort,
localStorage.setItem("sortNow", sortNow),
document.querySelectorAll(".cf-new-add").forEach(el=>el.remove()),
container.innerHTML = "",
changeUrl = localStorage.getItem("urlNow"),
initFriendCircle(sortNow, changeUrl),
fdata.apiurl && checkVersion()
}
function openMeShow(event) {
event.preventDefault();
var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/
, meLink = event.currentTarget.dataset.link.replace(parse_url, "$1:$2$3");
console.log(meLink);
var fetchUrl = "";
fetchUrl = fdata.apiurl ? fdata.apiurl + "post?num=5&link=" + meLink : fdata.apipublieurl + "post?num=5&link=" + meLink,
"ok" == noClick && (noClick = "no",
fetchShow(fetchUrl))
}
function closeShow() {
document.getElementById("cf-overlay").className -= "cf-show-now",
document.getElementById("cf-overshow").className -= "cf-show-now",
document.getElementById("cf-overshow").innerHTML = ""
}
localSortNow && localUrlNow ? (sortNow = localSortNow,
UrlNow = localUrlNow) : (sortNow = fdata.article_sort,
UrlNow = fdata.jsonurl ? fdata.apipublieurl + "postjson?jsonlink=" + fdata.jsonurl + "&" : fdata.apiurl ? fdata.apiurl + "all?" : fdata.apipublieurl + "all?",
console.log("当前模式:" + UrlNow),
localStorage.setItem("urlNow", UrlNow),
localStorage.setItem("sortNow", sortNow));
var noClick = "ok";
function openToShow() {
var fetchUrl = "";
fetchUrl = fdata.apiurl ? fdata.apiurl + "post" : fdata.apipublieurl + "post",
"ok" == noClick && (noClick = "no",
fetchShow(fetchUrl))
}
function fetchShow(url) {
var closeHtml = '\n      <div class="cf-overshow-close" onclick="closeShow()"></div>\n    ';
document.getElementById("cf-overlay").className = "cf-show-now",
document.getElementById("cf-overshow").insertAdjacentHTML("afterbegin", closeHtml),
console.log("开往" + url),
fetch(url).then(res=>res.json()).then(json=>{
noClick = "ok";
var statisticalData = json.statistical_data
, articleData = eval(json.article_data);
loadFcircleShow(statisticalData, articleData)
}
)
}
function initFriendCircle(sortNow, changeUrl) {
var articleSortData = sortNow + "ArticleData"
, localStatisticalData = JSON.parse(localStorage.getItem("statisticalData"))
, localArticleData = JSON.parse(localStorage.getItem(articleSortData));
if (container.innerHTML = "",
localStatisticalData && localArticleData) {
loadStatistical(localStatisticalData),
loadArticleItem(localArticleData, 0, fdata.initnumber),
console.log("本地数据加载成功");
var fetchUrl = UrlNow + "rule=" + sortNow + "&start=0&end=" + fdata.initnumber;
fetch(fetchUrl).then(res=>res.json()).then(json=>{
var statisticalData = json.statistical_data
, articleData = eval(json.article_data)
, localSnum = localStatisticalData.article_num
, newSnum = statisticalData.article_num
, localAtile = localArticleData[0].title
, newAtile = articleData[0].title;
if (localSnum !== newSnum || localAtile !== newAtile) {
document.getElementById("cf-state").remove(),
document.getElementById("cf-more").remove(),
document.getElementById("cf-footer").remove(),
container.innerHTML = "";
var articleSortData = sortNow + "ArticleData";
loadStatistical(statisticalData),
loadArticleItem(articleData, 0, fdata.initnumber),
localStorage.setItem("statisticalData", JSON.stringify(statisticalData)),
localStorage.setItem(articleSortData, JSON.stringify(articleData)),
console.log("热更新完成")
} else
console.log("API数据未更新")
}
)
} else
FetchFriendCircle(sortNow, changeUrl),
console.log("第一次加载完成")
}
initFriendCircle(sortNow);

sc.js

    var fdataUser = {
apiurl: 'https://moments.anxkj.top/'
};
var article_index = '',
article_title = '',
article_link = '',
article_author = '',
article_avatar = '',
article_time = '',
article_pwd = '';
var savedArticlesIndex = '';
var catchNowTime = Date.now();
var updateTime = localStorage.getItem("updateTime");
updateTime == null || catchNowTime - updateTime < 86400000 ? null : localStorage.removeItem("savedArticles");//每隔1天刷新一次
var savedArticles = localStorage.getItem("savedArticles");
if (savedArticles != null) {
console.log("内存读取成功");
var savedArticlesJson = JSON.parse(savedArticles)
addArticleCard(savedArticlesJson);
savedArticlesIndex = savedArticlesJson.map(item => item.index);
} else {
fetch("https://sc.api.anxkj.top/getsavedtitles?mode=all&column=&value=&output=jsonp")
.then(response => response.json())
.then(data => {
if (data.code == 200) {
console.log('获取收藏夹成功');
savedArticles = data.content;
localStorage.setItem("updateTime", catchNowTime);
localStorage.setItem("savedArticles", JSON.stringify(savedArticles));
console.log(savedArticles);
addArticleCard(savedArticles);
savedArticlesIndex = savedArticles.map(item => item.index);
console.log(savedArticlesIndex);
checkStared(savedArticlesIndex);
} else {
console.log('获取收藏夹失败')
}
})
.catch(error => {
console.error('获取收藏夹失败', error);
})
}
function checkStared(s) {
for (let i = 0; i < s.length; i++) {
var j = document.querySelector("#cf-container ." + s[i] + " .cf-star");
if (j) {
j.classList.contains("saved") ? null : j.classList.add("saved");
}
}
}
function addArticleCard(a) {
var container = '';
for (let i=0; i<a.length; i++) {
var item = a[i];
container += `
<div class="cf-article ${item.index}">
<a class="cf-article-title" href="${item.link}" target="_blank" rel="noopener nofollow" data-title="${item.title}">${item.title}</a>
<a class="cf-star saved" onclick="switchSecretInput(event)"><i class="fa fa-star"></i></a>
<div class="cf-article-avatar no-lightbox flink-item-icon">
<img class="cf-img-avatar avatar" src="${item.avatar}" alt="avatar" onerror="this.src=''; this.onerror = null;">
<a class="" target="_blank" rel="noopener nofollow"><span class="cf-article-author">${item.author}</span></a>
</div>
<span class="cf-article-time">
<span class="cf-time-created">${item.time}</span>
</span>
</div>
`;
}
document.getElementById("cf-saved-post").insertAdjacentHTML('beforeend', container);
}
function switchSecretInput(event) {
const a = document.getElementById("fcircleInputBox");
const b = a.querySelector(".input-password");
const f = a.querySelector(".content-body .title");
function c(e) { article_pwd = e.target.value; }
if (a.classList.contains("open")) {
a.classList.remove("open");
b.removeEventListener('input', c);
article_index = '';
article_title = '';
article_link = '';
article_author = '';
article_avatar = '';
article_time = '';
} else {
a.classList.add("open");
b.addEventListener('input', c);
var d = '';
if (event.target.nodeName.toUpperCase() == "A") {
if (event.target.classList.contains("saved")) {
sendMode = 1;
f.innerHTML = "移出收藏";
} else {
sendMode = 0;
f.innerHTML = "添加收藏";
}
d = event.target.parentElement.querySelector(".cf-article-title");
article_author = event.target.parentElement.querySelector(".cf-article-avatar .cf-article-author").innerText;
article_avatar = event.target.parentElement.querySelector(".cf-article-avatar .cf-img-avatar").src;
article_time = event.target.parentElement.querySelector(".cf-article-time .cf-time-created").innerText;
} else if (event.target.nodeName.toUpperCase() == "I") {
if (event.target.parentElement.classList.contains("saved")) {
sendMode = 1;
f.innerHTML = "移出收藏";
} else {
sendMode = 0;
f.innerHTML = "添加收藏";
}
d = event.target.parentElement.parentElement.querySelector(".cf-article-title");
article_author = event.target.parentElement.parentElement.querySelector(".cf-article-avatar .cf-article-author").innerText;
article_avatar = event.target.parentElement.parentElement.querySelector(".cf-article-avatar .cf-img-avatar").src;
article_time = event.target.parentElement.parentElement.querySelector(".cf-article-time .cf-time-created").innerText;
}
article_title = d.innerText;
article_link = d.getAttribute("href");
article_index = "cf-" + CryptoJS.MD5(article_link).toString();
}
}
function sendSubscribeInfo() {
var key = CryptoJS.SHA256(article_pwd);
var url = sendMode == 1
? "https://sc.api.anxkj.top/delsavedtitles?key=" + key + "&index=" + article_index
: "https://sc.api.anxkj.top/subscribe?key=" + key + "&index=" + article_index + "&title=" + article_title + "&link=" + article_link + "&author=" + article_author + "&avatar=" + article_avatar + "&time=" + article_time;
var inputBox = document.querySelector("#fcircleInputBox .inputBox");
var noteBox = document.querySelector("#fcircleInputBox .noteBox");
inputBox.classList.add("hide");
noteBox.classList.remove("hide");
fetch(url)
.then(response => response.json())
.then(data => {
if (data.code == 200) {
var a = document.querySelector("#cf-saved-post ." + article_index);
if (a) { a.outerHTML = ""; }
var b = document.querySelector("." + article_index + " .cf-star");
if (typeof savedArticlesIndex != 'undefined') savedArticlesIndex = savedArticlesIndex.filter(element => element !== article_index);
if (b) {b.classList.contains("saved") ? b.classList.remove("saved") : b.classList.add("saved");}
if (sendMode == 0) {
var container = `
<div class="cf-article ${article_index}">
<a class="cf-article-title" href="${article_link}" target="_blank" rel="noopener nofollow" data-title="${article_title}">${article_title}</a>
<a class="cf-star saved" onclick="switchSecretInput(event)"><i class="fa  fa-star"></i></a>
<div class="cf-article-avatar no-lightbox flink-item-icon">
<img class="cf-img-avatar avatar" src="${article_avatar}" alt="avatar" onerror="this.src=''; this.onerror = null;">
<a class="" target="_blank" rel="noopener nofollow"><span class="cf-article-author">${article_author}</span></a>
</div>
<span class="cf-article-time">
<span class="cf-time-created">${article_time}</span>
</span>
</div>
`;
document.getElementById("cf-saved-post").insertAdjacentHTML('beforeend', container);
}
tools.showMessage(data.message, "success", 2);
localStorage.removeItem("savedArticles");
inputBox.classList.remove("hide");
noteBox.classList.add("hide");
document.querySelector("#fcircleInputBox .btn.close").click();
} else {
tools.showMessage(data.message, "error", 2);
inputBox.classList.remove("hide");
noteBox.classList.add("hide");
document.querySelector("#fcircleInputBox .btn.close").click();
}
})
.catch(error => {
console.error('收藏失败:', error);
})
}
function foldSavedArticles(event) {
var a = document.getElementById("cf-saved-post")
var b = event.target.parentElement.querySelector("i")
if (b.style.transform == "rotate(180deg)") {
a.style.maxHeight = "240px"
b.style.transform = ""
} else {
a.style.maxHeight = typeof savedArticlesIndex != 'undefined' ? (savedArticlesIndex.length * 130 - 20) + "px" : "fit-content"
b.style.transform = "rotate(180deg)"
}
}

更新内容

2024.02.12 20:12
  • 修复图标无法显示
  • 修复弹窗无法显示
  • 修复无法收藏
  • 修复朋友圈api与收藏api冲突
2024.02.12 17:00

初步完成

© 版权声明
WWW.ANXKJ.TOP
喜欢就支持一下吧
点赞7 分享
评论 共2条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片