first commit

This commit is contained in:
root
2026-03-21 17:04:18 +08:00
commit 3c38481573
617 changed files with 65539 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
usr/plugins/AISummary/

1
.htaccess Normal file
View File

@@ -0,0 +1 @@

1
.user.ini Normal file
View File

@@ -0,0 +1 @@
open_basedir=/www/wwwroot/www.beihong.wang/:/tmp/

7
404.html Normal file
View File

@@ -0,0 +1,7 @@
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

282
LICENSE.txt Executable file
View File

@@ -0,0 +1,282 @@
The GNU General Public License (GPL)
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

70
README.md Normal file
View File

@@ -0,0 +1,70 @@
# Typecho 网站结构说明
这是基于 HarmonyHues 主题的 Typecho 博客站点,目录结构如下:
## 根目录(`/www/wwwroot/www.beihong.wang`
- `index.php``index.html`:前端入口文件。
- `config.inc.php`Typecho 配置(数据库、站点信息等)。
- `install.php``install/`:安装程序及脚本。
- 静态资源:`404.html``LICENSE.txt``img/` 等。
## 管理后台(`/admin`
包含所有后台页面和资源,用于登录、发布文章、安装插件、修改主题等。
- 各种 PHP 页面 (`manage-posts.php``options-theme.php` 等)。
- `css/``js/``img/` 子目录存放后台所需的样式、脚本与图片。
## 用户资源(`/usr`
- `themes/`:主题目录,当前使用 `HarmonyHues`
- `core/`:主题基础功能、配置。
- `components/`:各类组件与小部件。
- `assets/`前端静态资源CSS、JS、图片、一言文本等
- `install/``functions.php` 等辅助文件。
- `plugins/`:已安装的插件,例如 AISummary、MarkdownParse 等。
- `uploads/`:用户上传内容,按照年份/月划分(如 `2026/`)。
## 核心代码(`/var`
Typecho 系统运行时代码库:
- `Typecho/``Utils/``Widget/` 等子目录,包含框架核心、数据库接口、帮助函数等。
- `IXR/`XMLRPC 实现,用于远程发布。
## 说明
- 遇到功能问题时可根据上述结构定位相关文件。例如,
- 一言组件在 `usr/themes/HarmonyHues/components/widgets/widget-yiyan.php`
- 本地资源应使用文件路径,而非通过 URL 访问。
- `/usr/themes/HarmonyHues` 主题目录包含所有与页面显示相关内容,便于定制。
- `/admin` 提供完整的后台管理界面。
如需进一步分析插件、数据库结构或调试,
可在这些目录中查找对应文件或脚本。
## 更新日志
- 2026-03-03新增天气小部件功能。
1. 主题 `components/widgets/widget-weather.php` 添加天气查询代码,支持缓存、城市和 API Key 配置。
2.`components/sidebar.php` 中包含天气组件。
3. `core/theme-config.php` 增加 `ShowSidebarWeather` 选项以及 `weatherCity``weatherApiKey` 配置项。
4. 风格与一言组件一致;请输入有效 API Key 并在后台启用侧边栏“天气”模块。
5. 修改前已通过 `tar` 备份主题文件,备份包位于 `usr/themes/HarmonyHues-backup-2026-03-03.tar.gz`
- 更详细的实现步骤及说明可参考在其它聊天记录的说明。
- 2026-03-03天气模块进一步增强。
* 缓存结构升级,城市改变后立即生效并在后台保存查询城市。
* 城市名称支持中英文互译,常见城市输入英文也能显示中文名。
* 显示中文描述保持不变,增加体感温度、湿度、气压、风速/风向等信息。
* 加入 OpenWeatherMap 图标,优化字体、行高、布局与对齐,使输出居中且更协调。
* 注释和调试输出更详细,方便开发者阅读与排查。
### 注意事项
- 请使用 **有效的天气 API Key**。上述 key `464032d12749b7c0df937df0215af884` 返回错误“Invalid API key”说明并非 OpenWeatherMap 认可的密钥。访问 https://openweathermap.org/ 获取或检查你的帐号密钥。
- 也可以替换为其他天气服务(和风、心知等),只需改写 `widget-weather.php` 中的请求 URL 和参数。
- 错误信息会在侧边栏显示便于调试。

107
admin/backup.php Executable file
View File

@@ -0,0 +1,107 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$actionUrl = $security->getTokenUrl(
\Typecho\Router::url('do', array('action' => 'backup', 'widget' => 'Backup'),
\Typecho\Common::url('index.php', $options->rootUrl)));
$backupFiles = \Widget\Backup::alloc()->listFiles();
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 col-tb-8">
<div id="typecho-welcome">
<form action="<?php echo $actionUrl; ?>" method="post">
<h3><?php _e('备份您的数据'); ?></h3>
<ul>
<li><?php _e('此备份操作仅包含<strong>内容数据</strong>, 并不会涉及任何<strong>设置信息</strong>'); ?></li>
<li><?php _e('如果您的数据量过大, 为了避免操作超时, 建议您直接使用数据库提供的备份工具备份数据'); ?></li>
<li><strong class="warning"><?php _e('为了缩小备份文件体积, 建议您在备份前删除不必要的数据'); ?></strong></li>
</ul>
<p><button class="btn primary" type="submit"><?php _e('开始备份 &raquo;'); ?></button></p>
<input tabindex="1" type="hidden" name="do" value="export">
</form>
</div>
</div>
<div id="backup-secondary" class="col-mb-12 col-tb-4" role="form">
<h3><?php _e('恢复数据'); ?></h3>
<ul class="typecho-option-tabs">
<li class="active w-50"><a href="#from-upload"><?php _e('上传'); ?></a></li>
<li class="w-50"><a href="#from-server"><?php _e('从服务器'); ?></a></li>
</ul>
<form action="<?php echo $actionUrl; ?>" id="from-upload" class="tab-content" method="post" enctype="multipart/form-data">
<ul class="typecho-option">
<li>
<input tabindex="2" id="backup-upload-file" name="file" type="file" class="file">
</li>
</ul>
<ul class="typecho-option typecho-option-submit">
<li>
<button tabindex="4" type="submit" class="btn primary"><?php _e('上传并恢复 &raquo;'); ?></button>
<input type="hidden" name="do" value="import">
</li>
</ul>
</form>
<form action="<?php echo $actionUrl; ?>" id="from-server" class="tab-content hidden" method="post">
<?php if (empty($backupFiles)): ?>
<ul class="typecho-option">
<li>
<p class="description"><?php _e('将备份文件手动上传至服务器的 %s 目录下后, 这里会出现文件选项', __TYPECHO_BACKUP_DIR__); ?></p>
</li>
</ul>
<?php else: ?>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="backup-select-file"><?php _e('选择一个备份文件恢复数据'); ?></label>
<select tabindex="5" name="file" id="backup-select-file">
<?php foreach ($backupFiles as $file): ?>
<option value="<?php echo $file; ?>"><?php echo $file; ?></option>
<?php endforeach; ?>
</select>
</li>
</ul>
<?php endif; ?>
<ul class="typecho-option typecho-option-submit">
<li>
<button tabindex="7" type="submit" class="btn primary"><?php _e('选择并恢复 &raquo;'); ?></button>
<input type="hidden" name="do" value="import">
</li>
</ul>
</form>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
?>
<script>
$('#backup-secondary .typecho-option-tabs li').click(function() {
$('#backup-secondary .typecho-option-tabs li').removeClass('active');
$(this).addClass('active');
$(this).parents('#backup-secondary').find('.tab-content').addClass('hidden');
var selected_tab = $(this).find('a').attr('href');
$(selected_tab).removeClass('hidden');
return false;
});
$('#backup-secondary form').submit(function (e) {
if (!confirm('<?php _e('恢复操作将清除所有现有数据, 是否继续?'); ?>')) {
return false;
}
});
</script>
<?php include 'footer.php'; ?>

23
admin/category.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-6 col-tb-offset-3">
<?php \Widget\Metas\Category\Edit::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'footer.php';
?>

73
admin/common-js.php Executable file
View File

@@ -0,0 +1,73 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<script src="<?php $options->adminStaticUrl('js', 'jquery.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'jquery-ui.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'typecho.js'); ?>"></script>
<script>
(function () {
$(document).ready(function() {
// 处理消息机制
(function () {
var prefix = '<?php echo \Typecho\Cookie::getPrefix(); ?>',
cookies = {
notice : $.cookie(prefix + '__typecho_notice'),
noticeType : $.cookie(prefix + '__typecho_notice_type'),
highlight : $.cookie(prefix + '__typecho_notice_highlight')
},
path = '<?php echo \Typecho\Cookie::getPath(); ?>',
domain = '<?php echo \Typecho\Cookie::getDomain(); ?>',
secure = <?php echo json_encode(\Typecho\Cookie::getSecure()); ?>;
if (!!cookies.notice && 'success|notice|error'.indexOf(cookies.noticeType) >= 0) {
var head = $('.typecho-head-nav'),
p = $('<div class="message popup ' + cookies.noticeType + '">'
+ '<ul><li>' + $.parseJSON(cookies.notice).join('</li><li>')
+ '</li></ul></div>'), offset = 0;
if (head.length > 0) {
p.insertAfter(head);
} else {
p.prependTo(document.body);
}
p.slideDown(function () {
var t = $(this), color = '#C6D880';
if (t.hasClass('error')) {
color = '#FBC2C4';
} else if (t.hasClass('notice')) {
color = '#FFD324';
}
t.effect('highlight', {color : color})
.delay(5000).fadeOut(function () {
$(this).remove();
});
});
$.cookie(prefix + '__typecho_notice', null, {path : path, domain: domain, secure: secure});
$.cookie(prefix + '__typecho_notice_type', null, {path : path, domain: domain, secure: secure});
}
if (cookies.highlight) {
$('#' + cookies.highlight).effect('highlight', 1000);
$.cookie(prefix + '__typecho_notice_highlight', null, {path : path, domain: domain, secure: secure});
}
})();
if ($('.typecho-login').length == 0) {
$('a').each(function () {
var t = $(this), href = t.attr('href');
if ((href && href[0] == '#')
|| /^<?php echo preg_quote($options->adminUrl, '/'); ?>.*$/.exec(href)
|| /^<?php echo substr(preg_quote(\Typecho\Common::url('s', $options->index), '/'), 0, -1); ?>action\/[_a-zA-Z0-9\/]+.*$/.exec(href)) {
return;
}
t.attr('target', '_blank')
.attr('rel', 'noopener noreferrer');
});
}
});
})();
</script>

54
admin/common.php Executable file
View File

@@ -0,0 +1,54 @@
<?php
if (!defined('__DIR__')) {
define('__DIR__', dirname(__FILE__));
}
define('__TYPECHO_ADMIN__', true);
/** 载入配置文件 */
if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once __DIR__ . '/../config.inc.php') {
file_exists(__DIR__ . '/../install.php') ? header('Location: ../install.php') : print('Missing Config File');
exit;
}
/** 初始化组件 */
\Widget\Init::alloc();
/** 注册一个初始化插件 */
\Typecho\Plugin::factory('admin/common.php')->call('begin');
\Widget\Options::alloc()->to($options);
\Widget\User::alloc()->to($user);
\Widget\Security::alloc()->to($security);
\Widget\Menu::alloc()->to($menu);
/** 初始化上下文 */
$request = $options->request;
$response = $options->response;
/** 检测是否是第一次登录 */
$currentMenu = $menu->getCurrentMenu();
if (!empty($currentMenu)) {
$params = parse_url($currentMenu[2]);
$adminFile = basename($params['path']);
if (!$user->logged && !\Typecho\Cookie::get('__typecho_first_run')) {
if ('welcome.php' != $adminFile) {
$response->redirect(\Typecho\Common::url('welcome.php', $options->adminUrl));
} else {
\Typecho\Cookie::set('__typecho_first_run', 1);
}
} elseif ($user->pass('administrator', true)) {
/** 检测版本是否升级 */
$mustUpgrade = version_compare(\Typecho\Common::VERSION, $options->version, '>');
if ($mustUpgrade && 'upgrade.php' != $adminFile && 'backup.php' != $adminFile) {
$response->redirect(\Typecho\Common::url('upgrade.php', $options->adminUrl));
} elseif (!$mustUpgrade && 'upgrade.php' == $adminFile) {
$response->redirect($options->adminUrl);
} elseif (!$mustUpgrade && 'welcome.php' == $adminFile && $user->logged) {
$response->redirect($options->adminUrl);
}
}
}

13
admin/copyright.php Executable file
View File

@@ -0,0 +1,13 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<footer class="typecho-foot" role="contentinfo">
<div class="copyright">
<a href="https://typecho.org" class="i-logo-s">Typecho</a>
<p><?php _e('由 <a href="https://typecho.org">%s</a> 强力驱动, 版本 %s', $options->software, $options->version); ?></p>
</div>
<nav class="resource">
<a href="https://docs.typecho.org"><?php _e('帮助文档'); ?></a> &bull;
<a href="https://forum.typecho.org"><?php _e('支持论坛'); ?></a> &bull;
<a href="https://github.com/typecho/typecho/issues"><?php _e('报告错误'); ?></a> &bull;
<a href="https://typecho.org/download"><?php _e('资源下载'); ?></a>
</nav>
</footer>

1
admin/css/grid.css Executable file

File diff suppressed because one or more lines are too long

1
admin/css/install.css Executable file
View File

@@ -0,0 +1 @@
h1{text-align:center}details summary{cursor:pointer}@keyframes fadein{from{opacity:0}to{opacity:1}}.fresh .keep-word{display:none}.keep .fresh-word{display:none}form>.message{display:none;padding:20px;border-radius:5px}.message textarea{width:100%;height:200px;resize:none;margin:10px 0}.message.fade{display:block;animation:fadein .5s linear}.message *:last-child{margin-bottom:0}.message p{margin-top:10px}.message p button{margin-left:5px}.message p button:first-child{margin-left:0}

342
admin/css/normalize.css vendored Executable file
View File

@@ -0,0 +1,342 @@
/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-moz-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

1
admin/css/style.css Executable file

File diff suppressed because one or more lines are too long

36
admin/custom-fields-js.php Executable file
View File

@@ -0,0 +1,36 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<script>
$(document).ready(function () {
// 自定义字段
function attachDeleteEvent (el) {
$('button.btn-xs', el).click(function () {
if (confirm('<?php _e('确认要删除此字段吗?'); ?>')) {
$(this).parents('li').fadeOut(function () {
$(this).remove();
});
$(this).parents('form').trigger('change');
}
});
}
$('#custom-field .fields .field').each(function () {
attachDeleteEvent(this);
});
$('#custom-field button.operate-add').click(function () {
var html = '<li class="field"><div class="field-name"><input type="text" name="fieldNames[]" placeholder="<?php _e('字段名称'); ?>" pattern="^[_a-zA-Z][_a-zA-Z0-9]*$" oninput="this.reportValidity()" class="text-s w-100">'
+ '<select name="fieldTypes[]" id="">'
+ '<option value="str"><?php _e('字符'); ?></option>'
+ '<option value="int"><?php _e('整数'); ?></option>'
+ '<option value="float"><?php _e('小数'); ?></option>'
+ '<option value="json"><?php _e('JSON 结构'); ?></option>'
+ '</select></div>'
+ '<div class="field-value"><textarea name="fieldValues[]" placeholder="<?php _e('字段值'); ?>" class="text-s w-100" rows="2"></textarea>'
+ '<button type="button" class="btn btn-xs"><?php _e('删除'); ?></button></div></li>',
el = $(html).hide().appendTo('#custom-field .fields').fadeIn();
attachDeleteEvent(el);
});
});
</script>

72
admin/custom-fields.php Executable file
View File

@@ -0,0 +1,72 @@
<?php if (!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php
$fields = isset($post) ? $post->getFieldItems() : $page->getFieldItems();
$defaultFields = isset($post) ? $post->getDefaultFieldItems() : $page->getDefaultFieldItems();
?>
<details id="custom-field"
class="typecho-post-option" <?php if (!empty($defaultFields) || !empty($fields)): ?>open<?php endif; ?>>
<summary><?php _e('自定义字段'); ?></summary>
<ul class="fields mono">
<?php foreach ($defaultFields as $field): ?>
<?php [$label, $input] = $field; ?>
<li class="field">
<div class="field-name"><?php $label->render(); ?></div>
<div class="field-value"><?php $input->render(); ?></div>
</li>
<?php endforeach; ?>
<?php foreach ($fields as $field): ?>
<li class="field">
<div class="field-name">
<label for="fieldname" class="sr-only"><?php _e('字段名称'); ?></label>
<input type="text" name="fieldNames[]" value="<?php echo htmlspecialchars($field['name']); ?>"
id="fieldname" pattern="^[_a-zA-Z][_a-zA-Z0-9]*$" oninput="this.reportValidity()" class="text-s w-100">
<label for="fieldtype" class="sr-only"><?php _e('字段类型'); ?></label>
<select name="fieldTypes[]" id="fieldtype">
<option
value="str"<?php if ('str' == $field['type']): ?> selected<?php endif; ?>><?php _e('字符'); ?></option>
<option
value="int"<?php if ('int' == $field['type']): ?> selected<?php endif; ?>><?php _e('整数'); ?></option>
<option
value="float"<?php if ('float' == $field['type']): ?> selected<?php endif; ?>><?php _e('小数'); ?></option>
<option
value="json"<?php if ('json' == $field['type']): ?> selected<?php endif; ?>><?php _e('JSON 结构'); ?></option>
</select>
</div>
<div class="field-value">
<label for="fieldvalue" class="sr-only"><?php _e('字段值'); ?></label>
<textarea name="fieldValues[]" id="fieldvalue" class="text-s w-100"
rows="2"><?php echo htmlspecialchars($field[($field['type'] == 'json' ? 'str' : $field['type']) . '_value']); ?></textarea>
<button type="button" class="btn btn-xs"><?php _e('删除'); ?></button>
</div>
</li>
<?php endforeach; ?>
<?php if (empty($defaultFields) && empty($fields)): ?>
<li class="field">
<div class="field-name">
<label for="fieldname" class="sr-only"><?php _e('字段名称'); ?></label>
<input type="text" name="fieldNames[]" placeholder="<?php _e('字段名称'); ?>" id="fieldname"
class="text-s w-100" pattern="^[_a-zA-Z][_a-zA-Z0-9]*$" oninput="this.reportValidity()">
<label for="fieldtype" class="sr-only"><?php _e('字段类型'); ?></label>
<select name="fieldTypes[]" id="fieldtype">
<option value="str"><?php _e('字符'); ?></option>
<option value="int"><?php _e('整数'); ?></option>
<option value="float"><?php _e('小数'); ?></option>
<option value="json"><?php _e('JSON 结构'); ?></option>
</select>
</div>
<div class="field-value">
<label for="fieldvalue" class="sr-only"><?php _e('字段值'); ?></label>
<textarea name="fieldValues[]" placeholder="<?php _e('字段值'); ?>" id="fieldvalue"
class="text-s w-100" rows="2"></textarea>
<button type="button" class="btn btn-xs"><?php _e('删除'); ?></button>
</div>
</li>
<?php endif; ?>
</ul>
<div class="add">
<button type="button" class="btn btn-xs operate-add"><?php _e('+添加字段'); ?></button>
<div class="description kit-hidden-mb">
<?php _e('自定义字段可以扩展你的模板功能, 使用方法参见 <a href="https://docs.typecho.org/help/custom-fields">帮助文档</a>'); ?>
</div>
</div>
</details>

283
admin/editor-js.php Executable file
View File

@@ -0,0 +1,283 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php $content = !empty($post) ? $post : $page; ?>
<script>
(function () {
$('#text').on('change', function (e) {
e.preventDefault();
e.stopPropagation();
}).on('input', function () {
$(this).parents('form').trigger('write');
});
})();
</script>
<?php if (!$options->markdown): ?>
<script>
(function () {
const textarea = $('#text');
// 原始的插入图片和文件
Typecho.insertFileToEditor = function (file, url, isImage) {
const sel = textarea.getSelection(),
html = isImage ? '<img src="' + url + '" alt="' + file + '" />'
: '<a href="' + url + '">' + file + '</a>',
offset = (sel ? sel.start : 0) + html.length;
textarea.replaceSelection(html);
textarea.setSelection(offset, offset);
};
})();
</script>
<?php else: ?>
<script src="<?php $options->adminStaticUrl('js', 'hyperdown.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'pagedown.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
<script>
$(document).ready(function () {
const textarea = $('#text'),
toolbar = $('<div class="editor" id="wmd-button-bar" />').insertBefore(textarea.parent()),
preview = $('<div id="wmd-preview" class="wmd-hidetab" />').insertAfter('.editor');
let isFullScreen = false;
const options = {}, isMarkdown = <?php echo json_encode(!$content->have() || $content->isMarkdown); ?>;
options.strings = {
bold: '<?php _e('加粗'); ?> <strong> Ctrl+B',
boldexample: '<?php _e('加粗文字'); ?>',
italic: '<?php _e('斜体'); ?> <em> Ctrl+I',
italicexample: '<?php _e('斜体文字'); ?>',
link: '<?php _e('链接'); ?> <a> Ctrl+L',
linkdescription: '<?php _e('请输入链接描述'); ?>',
quote: '<?php _e('引用'); ?> <blockquote> Ctrl+Q',
quoteexample: '<?php _e('引用文字'); ?>',
code: '<?php _e('代码'); ?> <pre><code> Ctrl+K',
codeexample: '<?php _e('请输入代码'); ?>',
image: '<?php _e('图片'); ?> <img> Ctrl+G',
imagedescription: '<?php _e('请输入图片描述'); ?>',
olist: '<?php _e('数字列表'); ?> <ol> Ctrl+O',
ulist: '<?php _e('普通列表'); ?> <ul> Ctrl+U',
litem: '<?php _e('列表项目'); ?>',
heading: '<?php _e('标题'); ?> <h1>/<h2> Ctrl+H',
headingexample: '<?php _e('标题文字'); ?>',
hr: '<?php _e('分割线'); ?> <hr> Ctrl+R',
more: '<?php _e('摘要分割线'); ?> <!--more--> Ctrl+M',
undo: '<?php _e('撤销'); ?> - Ctrl+Z',
redo: '<?php _e('重做'); ?> - Ctrl+Y',
redomac: '<?php _e('重做'); ?> - Ctrl+Shift+Z',
fullscreen: '<?php _e('全屏'); ?> - Ctrl+J',
exitFullscreen: '<?php _e('退出全屏'); ?> - Ctrl+E',
fullscreenUnsupport: '<?php _e('此浏览器不支持全屏操作'); ?>',
imagedialog: '<p><b><?php _e('插入图片'); ?></b></p><p><?php _e('请在下方的输入框内输入要插入的远程图片地址'); ?></p><p><?php _e('您也可以使用附件功能插入上传的本地图片'); ?></p>',
linkdialog: '<p><b><?php _e('插入链接'); ?></b></p><p><?php _e('请在下方的输入框内输入要插入的链接地址'); ?></p>',
ok: '<?php _e('确定'); ?>',
cancel: '<?php _e('取消'); ?>',
help: '<?php _e('Markdown语法帮助'); ?>'
};
const converter = new HyperDown(),
editor = new Markdown.Editor(converter, '', options);
// 自动跟随
converter.enableHtml(true);
converter.enableLine(true);
const reloadScroll = scrollableEditor(textarea, preview);
// 修正白名单
converter.hook('makeHtml', function (html) {
html = html.replace('<p><!--more--></p>', '<!--more-->');
if (html.indexOf('<!--more-->') > 0) {
var parts = html.split(/\s*<\!\-\-more\-\->\s*/),
summary = parts.shift(),
details = parts.join('');
html = '<div class="summary">' + summary + '</div>'
+ '<div class="details">' + details + '</div>';
}
// 替换block
html = html.replace(/<(iframe|embed)\s+([^>]*)>/ig, function (all, tag, src) {
if (src[src.length - 1] === '/') {
src = src.substring(0, src.length - 1);
}
return '<div class="embed"><strong>'
+ tag + '</strong> : ' + $.trim(src) + '</div>';
});
return DOMPurify.sanitize(html, {USE_PROFILES: {html: true}});
});
editor.hooks.chain('onPreviewRefresh', function () {
const images = $('img', preview);
let count = images.length;
if (count === 0) {
reloadScroll(true);
} else {
images.bind('load error', function () {
count --;
if (count === 0) {
reloadScroll(true);
}
});
}
});
<?php \Typecho\Plugin::factory('admin/editor-js.php')->call('markdownEditor', $content); ?>
let th = textarea.height(), ph = preview.height();
const uploadBtn = $('<button type="button" id="btn-fullscreen-upload" class="btn btn-link">'
+ '<i class="i-upload"><?php _e('附件'); ?></i></button>')
.prependTo('.submit .right')
.click(function() {
$('a', $('.typecho-option-tabs li').not('.active')).trigger('click');
return false;
});
$('.typecho-option-tabs li').click(function () {
uploadBtn.find('i').toggleClass('i-upload-active',
$('#tab-files-btn', this).length > 0);
});
editor.hooks.chain('enterFakeFullScreen', function () {
th = textarea.height();
ph = preview.height();
$(document.body).addClass('fullscreen');
const h = $(window).height() - toolbar.outerHeight();
textarea.css('height', h);
preview.css('height', h);
isFullScreen = true;
});
editor.hooks.chain('enterFullScreen', function () {
$(document.body).addClass('fullscreen');
const h = window.screen.height - toolbar.outerHeight();
textarea.css('height', h);
preview.css('height', h);
isFullScreen = true;
});
editor.hooks.chain('exitFullScreen', function () {
$(document.body).removeClass('fullscreen');
textarea.height(th);
preview.height(ph);
isFullScreen = false;
});
editor.hooks.chain('commandExecuted', function () {
textarea.trigger('input');
});
editor.hooks.chain('save', function () {
Typecho.savePost();
});
function initMarkdown() {
editor.run();
const imageButton = $('#wmd-image-button'),
linkButton = $('#wmd-link-button');
Typecho.insertFileToEditor = function (file, url, isImage) {
const button = isImage ? imageButton : linkButton;
options.strings[isImage ? 'imagename' : 'linkname'] = file;
button.trigger('click');
let checkDialog = setInterval(function () {
if ($('.wmd-prompt-dialog').length > 0) {
$('.wmd-prompt-dialog input').val(url).select();
clearInterval(checkDialog);
checkDialog = null;
}
}, 10);
};
Typecho.uploadComplete = function (attachment) {
Typecho.insertFileToEditor(attachment.title, attachment.url, attachment.isImage);
};
// 编辑预览切换
const edittab = $('.editor').append('<div class="wmd-edittab"><a href="#wmd-editarea" class="active"><?php _e('撰写'); ?></a><a href="#wmd-preview"><?php _e('预览'); ?></a></div>'),
editarea = $(textarea.parent()).attr("id", "wmd-editarea");
$(".wmd-edittab a").click(function() {
$(".wmd-edittab a").removeClass('active');
$(this).addClass("active");
$("#wmd-editarea, #wmd-preview").addClass("wmd-hidetab");
const selected_tab = $(this).attr("href"),
selected_el = $(selected_tab).removeClass("wmd-hidetab");
// 预览时隐藏编辑器按钮
if (selected_tab === "#wmd-preview") {
$("#wmd-button-row").addClass("wmd-visualhide");
} else {
$("#wmd-button-row").removeClass("wmd-visualhide");
}
// 预览和编辑窗口高度一致
$("#wmd-preview").outerHeight($("#wmd-editarea").innerHeight());
return false;
});
// 剪贴板复制图片
textarea.bind('paste', function (e) {
const items = (e.clipboardData || e.originalEvent.clipboardData).items;
for (const item of items) {
if (item.kind === 'file') {
const file = item.getAsFile();
if (file.size > 0) {
if (!file.name) {
file.name = (new Date()).toISOString().replace(/\..+$/, '')
+ '.' + file.type.split('/').pop();
}
Typecho.uploadFile(file);
}
}
}
});
}
if (isMarkdown) {
initMarkdown();
} else {
const notice = $('<div class="message notice"><?php _e('这篇文章不是由Markdown语法创建的, 继续使用Markdown编辑它吗?'); ?> '
+ '<button class="btn btn-xs primary yes"><?php _e('是'); ?></button> '
+ '<button class="btn btn-xs no"><?php _e('否'); ?></button></div>')
.hide().insertBefore(textarea).slideDown();
$('.yes', notice).click(function () {
notice.remove();
$('<input type="hidden" name="markdown" value="1" />').appendTo('.submit');
initMarkdown();
});
$('.no', notice).click(function () {
notice.remove();
});
}
});
</script>
<?php endif; ?>

14
admin/extending.php Executable file
View File

@@ -0,0 +1,14 @@
<?php
include 'common.php';
$panel = $request->get('panel');
$panelTable = $options->panelTable;
if (!isset($panelTable['file']) || !in_array(urlencode($panel), $panelTable['file'])) {
throw new \Typecho\Plugin\Exception(_t('页面不存在'), 404);
}
[$pluginName, $file] = explode('/', trim($panel, '/'), 2);
require_once $options->pluginDir($pluginName) . '/' . $file;

240
admin/file-upload-js.php Executable file
View File

@@ -0,0 +1,240 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php
$phpMaxFilesize = function_exists('ini_get') ? trim(ini_get('upload_max_filesize')) : '0';
if (preg_match("/^([0-9]+)([a-z]{1,2})?$/i", $phpMaxFilesize, $matches)) {
$size = intval($matches[1]);
$unit = $matches[2] ?? 'b';
$phpMaxFilesize = round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
}
?>
<script>
$(document).ready(function() {
function updateAttachmentNumber () {
var btn = $('#tab-files-btn'),
balloon = $('.balloon', btn),
count = $('#file-list li .insert').length;
if (count > 0) {
if (!balloon.length) {
btn.html($.trim(btn.html()) + ' ');
balloon = $('<span class="balloon"></span>').appendTo(btn);
}
balloon.html(count);
} else if (0 === count && balloon.length > 0) {
balloon.remove();
}
}
updateAttachmentNumber();
const uploadUrl = $('.upload-area').bind({
dragenter : function (e) {
$(this).parent().addClass('drag');
},
dragover : function (e) {
e.stopPropagation();
e.preventDefault();
$(this).parent().addClass('drag');
},
drop : function (e) {
e.stopPropagation();
e.preventDefault();
$(this).parent().removeClass('drag');
const files = e.originalEvent.dataTransfer.files;
if (files.length === 0) {
return;
}
for (const file of files) {
Typecho.uploadFile(file);
}
},
dragend : function () {
$(this).parent().removeClass('drag');
},
dragleave : function () {
$(this).parent().removeClass('drag');
}
}).data('url');
const btn = $('.upload-file');
const fileInput = $('<input type="file" name="file" />').hide().insertAfter(btn);
btn.click(function () {
fileInput.click();
return false;
});
fileInput.change(function () {
if (this.files.length === 0) {
return;
}
Typecho.uploadFile(this.files[0]);
});
function fileUploadStart (file) {
$('<li id="' + file.id + '" class="loading">'
+ file.name + '</li>').appendTo('#file-list');
}
function fileUploadError (type, file) {
let word = '<?php _e('上传出现错误'); ?>';
switch (type) {
case 'size':
word = '<?php _e('文件大小超过限制'); ?>';
break;
case 'type':
word = '<?php _e('文件扩展名不被支持'); ?>';
break;
case 'duplicate':
word = '<?php _e('文件已经上传过'); ?>';
break;
case 'network':
default:
break;
}
var fileError = '<?php _e('%s 上传失败'); ?>'.replace('%s', file.name),
li, exist = $('#' + file.id);
if (exist.length > 0) {
li = exist.removeClass('loading').html(fileError);
} else {
li = $('<li>' + fileError + '<br />' + word + '</li>').appendTo('#file-list');
}
li.effect('highlight', {color : '#FBC2C4'}, 2000, function () {
$(this).remove();
});
}
function fileUploadComplete (file, attachment) {
const li = $('#' + file.id).removeClass('loading').data('cid', attachment.cid)
.data('url', attachment.url)
.data('image', attachment.isImage)
.html('<input type="hidden" name="attachment[]" value="' + attachment.cid + '" />'
+ '<a class="insert" target="_blank" href="###" title="<?php _e('点击插入文件'); ?>">'
+ attachment.title + '</a><div class="info">' + attachment.bytes
+ ' <a class="file" target="_blank" href="<?php $options->adminUrl('media.php'); ?>?cid='
+ attachment.cid + '" title="<?php _e('编辑'); ?>"><i class="i-edit"></i></a>'
+ ' <a class="delete" href="###" title="<?php _e('删除'); ?>"><i class="i-delete"></i></a></div>')
.effect('highlight', 1000);
attachInsertEvent(li);
attachDeleteEvent(li);
updateAttachmentNumber();
Typecho.uploadComplete(attachment);
}
Typecho.uploadFile = (function () {
const types = '<?php echo json_encode($options->allowedAttachmentTypes); ?>';
const maxSize = <?php echo $phpMaxFilesize ?>;
const queue = [];
let index = 0;
const getUrl = function () {
const url = new URL(uploadUrl);
const cid = $('input[name=cid]').val();
url.searchParams.append('cid', cid);
return url.toString();
};
const upload = function () {
const file = queue.shift();
if (!file) {
return;
}
const data = new FormData();
data.append('file', file);
fetch(getUrl(), {
method: 'POST',
body: data
}).then(function (response) {
if (response.ok) {
return response.json();
} else {
throw new Error(response.statusText);
}
}).then(function (data) {
if (data) {
const [_, attachment] = data;
fileUploadComplete(file, attachment);
upload();
} else {
throw new Error('no data');
}
}).catch(function (error) {
fileUploadError('network', file);
upload();
});
};
return function (file) {
file.id = 'upload-' + (index++);
if (file.size > maxSize) {
return fileUploadError('size', file);
}
const match = file.name.match(/\.([a-z0-9]+)$/i);
if (!match || types.indexOf(match[1].toLowerCase()) < 0) {
return fileUploadError('type', file);
}
queue.push(file);
fileUploadStart(file);
upload();
};
})();
function attachInsertEvent (el) {
$('.insert', el).click(function () {
var t = $(this), p = t.parents('li');
Typecho.insertFileToEditor(t.text(), p.data('url'), p.data('image'));
return false;
});
}
function attachDeleteEvent (el) {
var file = $('a.insert', el).text();
$('.delete', el).click(function () {
if (confirm('<?php _e('确认要删除文件 %s 吗?'); ?>'.replace('%s', file))) {
var cid = $(this).parents('li').data('cid');
$.post('<?php $security->index('/action/contents-attachment-edit'); ?>',
{'do' : 'delete', 'cid' : cid},
function () {
$(el).fadeOut(function () {
$(this).remove();
updateAttachmentNumber();
});
});
}
return false;
});
}
$('#file-list li').each(function () {
attachInsertEvent(this);
attachDeleteEvent(this);
});
});
</script>

32
admin/file-upload.php Executable file
View File

@@ -0,0 +1,32 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php
if (isset($post) || isset($page)) {
$cid = isset($post) ? $post->cid : $page->cid;
if ($cid) {
\Widget\Contents\Attachment\Related::alloc(['parentId' => $cid])->to($attachment);
} else {
\Widget\Contents\Attachment\Unattached::alloc()->to($attachment);
}
}
?>
<div id="upload-panel" class="p">
<div class="upload-area" data-url="<?php $security->index('/action/upload'); ?>">
<?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?>
</div>
<ul id="file-list">
<?php while ($attachment->next()): ?>
<li data-cid="<?php $attachment->cid(); ?>" data-url="<?php echo $attachment->attachment->url; ?>" data-image="<?php echo $attachment->attachment->isImage ? 1 : 0; ?>"><input type="hidden" name="attachment[]" value="<?php $attachment->cid(); ?>" />
<a class="insert" title="<?php _e('点击插入文件'); ?>" href="###"><?php $attachment->title(); ?></a>
<div class="info">
<?php echo number_format(ceil($attachment->attachment->size / 1024)); ?> Kb
<a class="file" target="_blank" href="<?php $options->adminUrl('media.php?cid=' . $attachment->cid); ?>" title="<?php _e('编辑'); ?>"><i class="i-edit"></i></a>
<a href="###" class="delete" title="<?php _e('删除'); ?>"><i class="i-delete"></i></a>
</div>
</li>
<?php endwhile; ?>
</ul>
</div>

7
admin/footer.php Executable file
View File

@@ -0,0 +1,7 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php \Typecho\Plugin::factory('admin/footer.php')->call('begin'); ?>
</body>
</html>
<?php
/** 注册一个结束插件 */
\Typecho\Plugin::factory('admin/footer.php')->call('end');

51
admin/form-js.php Executable file
View File

@@ -0,0 +1,51 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<script>
(function () {
$(document).ready(function () {
const error = $('.typecho-option .error:first');
if (error.length > 0) {
$('html,body').scrollTop(error.parents('.typecho-option').offset().top);
}
$('.main form').submit(function () {
const self = $(this);
if (self.hasClass('submitting')) {
return false;
} else {
$('button[type=submit]', this).attr('disabled', 'disabled');
self.addClass('submitting');
}
}).on('submitted', function () {
$('button[type=submit]', this).removeAttr('disabled');
$(this).removeClass('submitting');
});
$('label input[type=text]').click(function (e) {
const check = $('#' + $(this).parents('label').attr('for'));
check.prop('checked', true);
return false;
});
$('.main form input[type="url"]').each(function () {
const self = $(this);
const input = $('<input type="hidden" />').attr('name', self.attr('name'));
function setInput() {
const url = self.val();
try {
const urlObj = new URL(url);
input.val(urlObj.toString());
} catch {
// ignore
}
}
self.removeAttr('name').after(input).on('input', setInput);
setInput();
});
});
})();
</script>

23
admin/header.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
if (!defined('__TYPECHO_ADMIN__')) {
exit;
}
$header = '<link rel="stylesheet" href="' . $options->adminStaticUrl('css', 'normalize.css', true) . '">
<link rel="stylesheet" href="' . $options->adminStaticUrl('css', 'grid.css', true) . '">
<link rel="stylesheet" href="' . $options->adminStaticUrl('css', 'style.css', true) . '">';
/** 注册一个初始化插件 */
$header = \Typecho\Plugin::factory('admin/header.php')->filter('header', $header);
?><!DOCTYPE HTML>
<html>
<head>
<meta charset="<?php $options->charset(); ?>">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title><?php _e('%s - %s - Powered by Typecho', $menu->title, $options->title); ?></title>
<meta name="robots" content="noindex, nofollow">
<?php echo $header; ?>
</head>
<body<?php if (isset($bodyClass)) {echo ' class="' . $bodyClass . '"';} ?>>

BIN
admin/img/ajax-loader.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

BIN
admin/img/editor.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
admin/img/editor@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
admin/img/icons.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
admin/img/icons@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
admin/img/noscreen.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

10
admin/img/typecho-logo.svg Executable file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="110px" height="26px" viewBox="0 0 110 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<title>typecho-logo</title>
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M34.75,5.288 C34.288,6.542 33.76,7.73 32.22,7.862 L32,9.468 L33.562,9.468 L33.562,15.342 C33.562,16.882 33.54,18.994 36.972,18.994 C38.006,18.994 39.106,18.686 39.766,18.224 L39.106,16.53 C38.754,16.75 38.204,16.992 37.61,16.992 C36.708,16.992 36.18,16.596 36.18,15.254 L36.18,9.468 L38.886,9.468 L39.106,7.62 L36.18,7.62 L36.18,5.288 L34.75,5.288 Z M48.258,18.268 C48.258,20.27 47.444,21.502 45.42,21.502 C44.76,21.502 44.276,21.436 43.858,21.282 C43.462,21.128 43.352,20.908 43.352,20.49 L43.352,19.434 L41.262,19.61 L41.262,22.668 C42.186,23.13 44.012,23.394 45.398,23.394 C48.676,23.394 50.502,21.898 50.502,18.268 L50.502,7.62 L46.63,7.62 L46.63,9.424 L47.334,9.468 C47.752,9.468 47.884,9.644 47.884,10.128 L47.884,14.11 C47.884,15.254 47.07,16.288 45.53,16.288 C44.122,16.288 43.902,15.276 43.902,13.934 L43.902,7.62 L40.03,7.62 L40.03,9.424 L40.734,9.468 C41.108,9.49 41.284,9.622 41.284,10.084 L41.284,14.506 C41.284,17.102 42.494,18.312 44.694,18.312 C46.146,18.312 47.488,17.696 48.258,16.596 L48.258,18.268 Z M54,20.776 C54,21.326 53.78,21.458 53.362,21.502 L52.636,21.568 L52.636,23.24 L58.312,23.24 L58.312,21.502 L56.53,21.414 L56.53,18.378 C57.102,18.73 58.026,19.016 58.884,19.016 C61.788,19.016 63.702,16.926 63.702,12.878 C63.702,8.94 62.162,7.29 59.72,7.29 C57.85,7.29 56.64,8.302 56.244,9.05 L56.244,7.62 L52.526,7.62 L52.526,9.402 L53.45,9.468 C53.868,9.468 54,9.644 54,10.128 L54,20.776 Z M60.974,13.098 C60.974,15.012 60.336,16.926 58.466,16.926 C57.894,16.926 57.102,16.75 56.53,16.376 L56.53,11.316 C56.53,10.304 57.498,9.424 58.752,9.424 C59.918,9.424 60.974,10.172 60.974,13.098 Z M70.786,7.29 C67.178,7.29 65.352,10.15 65.352,13.406 C65.352,16.684 66.804,18.972 70.544,18.972 C72.612,18.972 74.064,18.048 74.416,17.74 L73.58,15.958 C73.052,16.332 72.106,16.926 70.808,16.926 C68.938,16.926 68.19,15.76 68.102,14.33 C70.698,14.308 74.372,13.736 74.372,10.348 C74.372,8.39 72.942,7.29 70.786,7.29 Z M71.952,10.392 C71.952,12.086 69.642,12.46 68.014,12.482 C68.08,10.854 68.872,9.16 70.632,9.16 C71.424,9.16 71.952,9.578 71.952,10.392 Z M81.192,16.97 C79.234,16.97 78.354,15.43 78.354,13.032 C78.354,10.59 79.256,9.27 81.016,9.27 C81.346,9.27 81.61,9.314 81.874,9.402 C82.27,9.534 82.336,9.732 82.336,10.15 L82.336,11.206 L84.36,11.052 L84.36,8.192 C83.304,7.62 82.248,7.29 80.928,7.29 C78.442,7.29 75.692,8.83 75.692,13.296 C75.692,16.948 77.606,18.994 80.84,18.994 C82.468,18.994 83.81,18.422 84.668,17.718 L83.722,16.024 C82.82,16.684 82.05,16.97 81.192,16.97 Z M87.286,16.222 C87.286,16.772 87.066,16.904 86.648,16.948 L85.922,17.014 L85.922,18.686 L91.158,18.686 L91.158,16.926 L89.904,16.86 L89.904,11.536 C89.904,10.392 90.718,9.314 92.258,9.314 C93.666,9.314 93.974,10.348 93.974,11.69 L93.974,16.222 C93.974,16.772 93.754,16.904 93.336,16.948 L92.61,17.014 L92.61,18.686 L97.846,18.686 L97.846,16.926 L96.592,16.86 L96.592,11.118 C96.592,8.522 95.294,7.29 93.094,7.29 C91.642,7.29 90.542,7.972 89.882,8.918 L89.882,3 L85.966,3 L85.966,4.826 L86.736,4.87 C87.154,4.892 87.286,5.024 87.286,5.508 L87.286,16.222 Z M98.924,13.142 C98.924,17.124 100.86,19.016 103.808,19.016 C106.712,19.016 109.066,17.08 109.066,12.856 C109.066,7.796 105.788,7.29 104.16,7.29 C101.894,7.29 98.924,8.566 98.924,13.142 Z M103.984,17.08 C101.872,17.08 101.586,14.88 101.586,12.834 C101.586,10.722 102.29,9.226 104.028,9.226 C105.788,9.226 106.382,10.744 106.382,13.208 C106.382,15.496 105.7,17.08 103.984,17.08 Z" id="typecho" fill="#000000" sketch:type="MSShapeGroup"></path>
<path d="M13,26 C3.36833333,26 0,22.631 0,13 C0,3.36866667 3.36833333,0 13,0 C22.6316667,0 26,3.36866667 26,13 C26,22.631 22.6316667,26 13,26 Z M6,9 L20,9 L20,7 L6,7 L6,9 Z M6,14 L16,14 L16,12 L6,12 L6,14 Z M6,19 L18,19 L18,17 L6,17 L6,19 Z" id="icon" fill="#000000" sketch:type="MSShapeGroup"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

155
admin/index.php Executable file
View File

@@ -0,0 +1,155 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
?>
<main class="main">
<div class="container typecho-dashboard">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main">
<div class="col-mb-12 welcome-board" role="main">
<p><?php _e('目前有 <em>%s</em> 篇文章, 并有 <em>%s</em> 条关于你的评论在 <em>%s</em> 个分类中.',
$stat->myPublishedPostsNum, $stat->myPublishedCommentsNum, $stat->categoriesNum); ?>
<br><?php _e('点击下面的链接快速开始:'); ?></p>
<ul id="start-link">
<?php if ($user->pass('contributor', true)): ?>
<li><a href="<?php $options->adminUrl('write-post.php'); ?>"><?php _e('撰写新文章'); ?></a></li>
<?php if ($user->pass('editor', true) && 'on' == $request->get('__typecho_all_comments') && $stat->waitingCommentsNum > 0): ?>
<li>
<a href="<?php $options->adminUrl('manage-comments.php?status=waiting'); ?>"><?php _e('待审核的评论'); ?></a>
<span class="balloon"><?php $stat->waitingCommentsNum(); ?></span>
</li>
<?php elseif ($stat->myWaitingCommentsNum > 0): ?>
<li>
<a href="<?php $options->adminUrl('manage-comments.php?status=waiting'); ?>"><?php _e('待审核评论'); ?></a>
<span class="balloon"><?php $stat->myWaitingCommentsNum(); ?></span>
</li>
<?php endif; ?>
<?php if ($user->pass('editor', true) && 'on' == $request->get('__typecho_all_comments') && $stat->spamCommentsNum > 0): ?>
<li>
<a href="<?php $options->adminUrl('manage-comments.php?status=spam'); ?>"><?php _e('垃圾评论'); ?></a>
<span class="balloon"><?php $stat->spamCommentsNum(); ?></span>
</li>
<?php elseif ($stat->mySpamCommentsNum > 0): ?>
<li>
<a href="<?php $options->adminUrl('manage-comments.php?status=spam'); ?>"><?php _e('垃圾评论'); ?></a>
<span class="balloon"><?php $stat->mySpamCommentsNum(); ?></span>
</li>
<?php endif; ?>
<?php if ($user->pass('administrator', true)): ?>
<li><a href="<?php $options->adminUrl('themes.php'); ?>"><?php _e('更换外观'); ?></a></li>
<li><a href="<?php $options->adminUrl('plugins.php'); ?>"><?php _e('插件管理'); ?></a></li>
<li><a href="<?php $options->adminUrl('options-general.php'); ?>"><?php _e('系统设置'); ?></a>
</li>
<?php endif; ?>
<?php endif; ?>
<!--<li><a href="<?php $options->adminUrl('profile.php'); ?>"><?php _e('更新我的资料'); ?></a></li>-->
</ul>
</div>
<div class="col-mb-12 col-tb-4" role="complementary">
<section class="latest-link">
<h3><?php _e('最近发布的文章'); ?></h3>
<?php \Widget\Contents\Post\Recent::alloc('pageSize=10')->to($posts); ?>
<ul>
<?php if ($posts->have()): ?>
<?php while ($posts->next()): ?>
<li>
<span><?php $posts->date('n.j'); ?></span>
<a href="<?php $posts->permalink(); ?>" class="title"><?php $posts->title(); ?></a>
</li>
<?php endwhile; ?>
<?php else: ?>
<li><em><?php _e('暂时没有文章'); ?></em></li>
<?php endif; ?>
</ul>
</section>
</div>
<div class="col-mb-12 col-tb-4" role="complementary">
<section class="latest-link">
<h3><?php _e('最近得到的回复'); ?></h3>
<ul>
<?php \Widget\Comments\Recent::alloc('pageSize=10')->to($comments); ?>
<?php if ($comments->have()): ?>
<?php while ($comments->next()): ?>
<li>
<span><?php $comments->date('n.j'); ?></span>
<a href="<?php $comments->permalink(); ?>"
class="title"><?php $comments->author(false); ?></a>:
<?php $comments->excerpt(35, '...'); ?>
</li>
<?php endwhile; ?>
<?php else: ?>
<li><?php _e('暂时没有回复'); ?></li>
<?php endif; ?>
</ul>
</section>
</div>
<div class="col-mb-12 col-tb-4" role="complementary">
<section class="latest-link">
<h3><?php _e('官方最新日志'); ?></h3>
<div id="typecho-message">
<ul>
<li><?php _e('读取中...'); ?></li>
</ul>
</div>
</section>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
?>
<script>
$(document).ready(function () {
var ul = $('#typecho-message ul'), cache = window.sessionStorage,
html = cache ? cache.getItem('feed') : '',
update = cache ? cache.getItem('update') : '';
if (!!html) {
ul.html(html);
} else {
html = '';
$.get('<?php $options->index('/action/ajax?do=feed'); ?>', function (o) {
for (var i = 0; i < o.length; i++) {
var item = o[i];
html += '<li><span>' + item.date + '</span> <a href="' + item.link + '" target="_blank">' + item.title
+ '</a></li>';
}
ul.html(html);
cache.setItem('feed', html);
}, 'json');
}
function applyUpdate(update) {
if (update.available) {
$('<div class="update-check message error"><p>'
+ '<?php _e('您当前使用的版本是 %s'); ?>'.replace('%s', update.current) + '<br />'
+ '<strong><a href="' + update.link + '" target="_blank">'
+ '<?php _e('官方最新版本是 %s'); ?>'.replace('%s', update.latest) + '</a></strong></p></div>')
.insertAfter('.typecho-page-title').effect('highlight');
}
}
if (!!update) {
applyUpdate($.parseJSON(update));
} else {
$.get('<?php $options->index('/action/ajax?do=checkVersion'); ?>', function (o, status, resp) {
applyUpdate(o);
cache.setItem('update', resp.responseText);
}, 'json');
}
});
</script>
<?php include 'footer.php'; ?>

1
admin/js/hyperdown.js Executable file

File diff suppressed because one or more lines are too long

1
admin/js/jquery-ui.js vendored Executable file

File diff suppressed because one or more lines are too long

1
admin/js/jquery.js vendored Executable file

File diff suppressed because one or more lines are too long

1
admin/js/pagedown.js Executable file

File diff suppressed because one or more lines are too long

1
admin/js/purify.js Executable file

File diff suppressed because one or more lines are too long

1
admin/js/timepicker.js Executable file

File diff suppressed because one or more lines are too long

1
admin/js/tokeninput.js Executable file

File diff suppressed because one or more lines are too long

1
admin/js/typecho.js Executable file

File diff suppressed because one or more lines are too long

56
admin/login.php Executable file
View File

@@ -0,0 +1,56 @@
<?php
include 'common.php';
if ($user->hasLogin()) {
$response->redirect($options->adminUrl);
}
$rememberName = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_name', ''));
\Typecho\Cookie::delete('__typecho_remember_name');
$bodyClass = 'body-100';
include 'header.php';
?>
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="https://typecho.org" class="i-logo">Typecho</a></h1>
<form action="<?php $options->loginAction(); ?>" method="post" name="login" role="form">
<p>
<label for="name" class="sr-only"><?php _e('用户名或邮箱'); ?></label>
<input type="text" id="name" name="name" value="<?php echo $rememberName; ?>" placeholder="<?php _e('用户名或邮箱'); ?>" class="text-l w-100" autofocus />
</p>
<p>
<label for="password" class="sr-only"><?php _e('密码'); ?></label>
<input type="password" id="password" name="password" class="text-l w-100" placeholder="<?php _e('密码'); ?>" required />
</p>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('登录'); ?></button>
<input type="hidden" name="referer" value="<?php echo $request->filter('html')->get('referer'); ?>" />
</p>
<p>
<label for="remember">
<input<?php if(\Typecho\Cookie::get('__typecho_remember_remember')): ?> checked<?php endif; ?> type="checkbox" name="remember" class="checkbox" value="1" id="remember" /> <?php _e('下次自动登录'); ?>
</label>
</p>
</form>
<p class="more-link">
<a href="<?php $options->siteUrl(); ?>"><?php _e('返回首页'); ?></a>
<?php if($options->allowRegister): ?>
&bull;
<a href="<?php $options->registerUrl(); ?>"><?php _e('用户注册'); ?></a>
<?php endif; ?>
</p>
</div>
</div>
<?php
include 'common-js.php';
?>
<script>
$(document).ready(function () {
$('#name').focus();
});
</script>
<?php
include 'footer.php';
?>

169
admin/manage-categories.php Executable file
View File

@@ -0,0 +1,169 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
\Widget\Metas\Category\Admin::alloc()->to($categories);
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main manage-metas">
<div class="col-mb-12" role="main">
<form method="post" name="manage_categories" class="operate-form">
<div class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('此分类下的所有内容将被删除, 你确认要删除这些分类吗?'); ?>"
href="<?php $security->index('/action/metas-category-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
<li><a lang="<?php _e('刷新分类可能需要等待较长时间, 你确认要刷新这些分类吗?'); ?>"
href="<?php $security->index('/action/metas-category-edit?do=refresh'); ?>"><?php _e('刷新'); ?></a>
</li>
<li class="multiline">
<button type="button" class="btn merge btn-s"
rel="<?php $security->index('/action/metas-category-edit?do=merge'); ?>"><?php _e('合并到'); ?></button>
<select name="merge">
<?php $categories->parse('<option value="{mid}">{name}</option>'); ?>
</select>
</li>
</ul>
</div>
</div>
<div class="search" role="search">
<?php $categories->backLink(); ?>
</div>
</div>
<table class="typecho-list-table">
<colgroup>
<col width="3%" class="kit-hidden-mb"/>
<col width=""/>
<col width="15%" class="kit-hidden-mb"/>
<col width="20%"/>
<col width="15%"/>
<col width="15%" class="kit-hidden-mb"/>
</colgroup>
<thead>
<tr class="nodrag">
<th class="kit-hidden-mb"></th>
<th><?php _e('名称'); ?></th>
<th><?php _e('子分类'); ?></th>
<th class="kit-hidden-mb"><?php _e('缩略名'); ?></th>
<th></th>
<th class="kit-hidden-mb"><?php _e('文章数'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($categories->have()): ?>
<?php while ($categories->next()): ?>
<tr id="mid-<?php $categories->theId(); ?>">
<td class="kit-hidden-mb"><input type="checkbox"
value="<?php $categories->mid(); ?>"
name="mid[]"/></td>
<td>
<a href="<?php $options->adminUrl('category.php?mid=' . $categories->mid); ?>"><?php $categories->name(); ?></a>
<a href="<?php $categories->permalink(); ?>"
title="<?php _e('浏览 %s', $categories->name); ?>"><i class="i-exlink"></i></a>
</td>
<td>
<?php if (count($categories->children) > 0): ?>
<a href="<?php $options->adminUrl('manage-categories.php?parent=' . $categories->mid); ?>"><?php echo _n('一个分类', '%d个分类', count($categories->children)); ?></a>
<?php else: ?>
<a href="<?php $options->adminUrl('category.php?parent=' . $categories->mid); ?>"><?php echo _e('新增'); ?></a>
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><?php $categories->slug(); ?></td>
<td>
<?php if ($options->defaultCategory == $categories->mid): ?>
<?php _e('默认'); ?>
<?php else: ?>
<a class="hidden-by-mouse"
href="<?php $security->index('/action/metas-category-edit?do=default&mid=' . $categories->mid); ?>"
title="<?php _e('设为默认'); ?>"><?php _e('默认'); ?></a>
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><a
class="balloon-button left size-<?php echo \Typecho\Common::splitByCount($categories->count, 1, 10, 20, 50, 100); ?>"
href="<?php $options->adminUrl('manage-posts.php?category=' . $categories->mid); ?>"><?php $categories->count(); ?></a>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="6" class="none"><?php _e('没有任何分类'); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</form>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
?>
<script type="text/javascript">
(function () {
$(document).ready(function () {
var table = $('.typecho-list-table').tableDnD({
onDrop: function () {
var ids = [];
$('input[type=checkbox]', table).each(function () {
ids.push($(this).val());
});
$.post('<?php $security->index('/action/metas-category-edit?do=sort'); ?>',
$.param({mid: ids}));
$('tr', table).each(function (i) {
if (i % 2) {
$(this).addClass('even');
} else {
$(this).removeClass('even');
}
});
}
});
table.tableSelectable({
checkEl: 'input[type=checkbox]',
rowEl: 'tr',
selectAllEl: '.typecho-table-select-all',
actionEl: '.dropdown-menu a'
});
$('.btn-drop').dropdownMenu({
btnEl: '.dropdown-toggle',
menuEl: '.dropdown-menu'
});
$('.dropdown-menu button.merge').click(function () {
var btn = $(this);
btn.parents('form').attr('action', btn.attr('rel')).submit();
});
<?php if (isset($request->mid)): ?>
$('.typecho-mini-panel').effect('highlight', '#AACB36');
<?php endif; ?>
});
})();
</script>
<?php include 'footer.php'; ?>

373
admin/manage-comments.php Executable file
View File

@@ -0,0 +1,373 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
$comments = \Widget\Comments\Admin::alloc();
$isAllComments = ('on' == $request->get('__typecho_all_comments') || 'on' == \Typecho\Cookie::get('__typecho_all_comments'));
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 typecho-list">
<div class="typecho-list-operate">
<ul class="typecho-option-tabs">
<li<?php if(!isset($request->status) || 'approved' == $request->get('status')): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('manage-comments.php'
. (isset($request->cid) ? '?cid=' . $request->filter('encode')->cid : '')); ?>"><?php _e('已通过'); ?></a></li>
<li<?php if('waiting' == $request->get('status')): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('manage-comments.php?status=waiting'
. (isset($request->cid) ? '&cid=' . $request->filter('encode')->cid : '')); ?>"><?php _e('待审核'); ?>
<?php if(!$isAllComments && $stat->myWaitingCommentsNum > 0 && !isset($request->cid)): ?>
<span class="balloon"><?php $stat->myWaitingCommentsNum(); ?></span>
<?php elseif($isAllComments && $stat->waitingCommentsNum > 0 && !isset($request->cid)): ?>
<span class="balloon"><?php $stat->waitingCommentsNum(); ?></span>
<?php elseif(isset($request->cid) && $stat->currentWaitingCommentsNum > 0): ?>
<span class="balloon"><?php $stat->currentWaitingCommentsNum(); ?></span>
<?php endif; ?>
</a></li>
<li<?php if('spam' == $request->get('status')): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('manage-comments.php?status=spam'
. (isset($request->cid) ? '&cid=' . $request->filter('encode')->cid : '')); ?>"><?php _e('垃圾'); ?>
<?php if(!$isAllComments && $stat->mySpamCommentsNum > 0 && !isset($request->cid)): ?>
<span class="balloon"><?php $stat->mySpamCommentsNum(); ?></span>
<?php elseif($isAllComments && $stat->spamCommentsNum > 0 && !isset($request->cid)): ?>
<span class="balloon"><?php $stat->spamCommentsNum(); ?></span>
<?php elseif(isset($request->cid) && $stat->currentSpamCommentsNum > 0): ?>
<span class="balloon"><?php $stat->currentSpamCommentsNum(); ?></span>
<?php endif; ?>
</a></li>
</ul>
<?php if($user->pass('editor', true) && !isset($request->cid)): ?>
<ul class="typecho-option-tabs">
<li class="<?php if($isAllComments): ?> current<?php endif; ?>"><a href="<?php echo $request->makeUriByRequest('__typecho_all_comments=on'); ?>"><?php _e('所有'); ?></a></li>
<li class="<?php if(!$isAllComments): ?> current<?php endif; ?>"><a href="<?php echo $request->makeUriByRequest('__typecho_all_comments=off'); ?>"><?php _e('我的'); ?></a></li>
</ul>
<?php endif; ?>
</div>
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox" class="typecho-table-select-all" /></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a href="<?php $security->index('/action/comments-edit?do=approved'); ?>"><?php _e('通过'); ?></a></li>
<li><a href="<?php $security->index('/action/comments-edit?do=waiting'); ?>"><?php _e('待审核'); ?></a></li>
<li><a href="<?php $security->index('/action/comments-edit?do=spam'); ?>"><?php _e('标记垃圾'); ?></a></li>
<li><a lang="<?php _e('你确认要删除这些评论吗?'); ?>" href="<?php $security->index('/action/comments-edit?do=delete'); ?>"><?php _e('删除'); ?></a></li>
</ul>
<?php if('spam' == $request->get('status')): ?>
<button lang="<?php _e('你确认要删除所有垃圾评论吗?'); ?>" class="btn btn-s btn-warn btn-operate" href="<?php $security->index('/action/comments-edit?do=delete-spam'); ?>"><?php _e('删除所有垃圾评论'); ?></button>
<?php endif; ?>
</div>
</div>
<div class="search" role="search">
<?php if ('' != $request->keywords || '' != $request->category): ?>
<a href="<?php $options->adminUrl('manage-comments.php'
. (isset($request->status) || isset($request->cid) ? '?' .
(isset($request->status) ? 'status=' . $request->filter('encode')->status : '') .
(isset($request->cid) ? (isset($request->status) ? '&' : '') . 'cid=' . $request->filter('encode')->cid : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>" value="<?php echo $request->filter('html')->keywords; ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<?php if(isset($request->status)): ?>
<input type="hidden" value="<?php echo $request->filter('html')->status; ?>" name="status" />
<?php endif; ?>
<?php if(isset($request->cid)): ?>
<input type="hidden" value="<?php echo $request->filter('html')->cid; ?>" name="cid" />
<?php endif; ?>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
<form method="post" name="manage_comments" class="operate-form">
<table class="typecho-list-table">
<colgroup>
<col width="3%" class="kit-hidden-mb"/>
<col width="6%" class="kit-hidden" />
<col width="20%"/>
<col width="71%"/>
</colgroup>
<thead>
<tr>
<th class="kit-hidden-mb"> </th>
<th><?php _e('作者'); ?></th>
<th class="kit-hidden-mb"> </th>
<th><?php _e('内容'); ?></th>
</tr>
</thead>
<tbody>
<?php if($comments->have()): ?>
<?php while($comments->next()): ?>
<tr id="<?php $comments->theId(); ?>" data-comment="<?php
$comment = array(
'author' => $comments->author,
'mail' => $comments->mail,
'url' => $comments->url,
'ip' => $comments->ip,
'type' => $comments->type,
'text' => $comments->text
);
echo htmlspecialchars(json_encode($comment));
?>">
<td valign="top" class="kit-hidden-mb">
<input type="checkbox" value="<?php $comments->coid(); ?>" name="coid[]"/>
</td>
<td valign="top" class="kit-hidden">
<div class="comment-avatar">
<?php if ('comment' == $comments->type): ?>
<?php $comments->gravatar(40, null, true); ?>
<?php endif; ?>
<?php if ('comment' != $comments->type): ?>
<?php _e('引用'); ?>
<?php endif; ?>
</div>
</td>
<td valign="top" class="comment-head">
<div class="comment-meta">
<strong class="comment-author"><?php $comments->author(true); ?></strong>
<?php if($comments->mail): ?>
<br /><span><a href="<?php $comments->mail(true); ?>"><?php $comments->mail(); ?></a></span>
<?php endif; ?>
<?php if($comments->ip): ?>
<br /><span><?php $comments->ip(); ?></span>
<?php endif; ?>
</div>
</td>
<td valign="top" class="comment-body">
<div class="comment-date"><?php $comments->dateWord(); ?> 于 <a href="<?php $comments->permalink(); ?>"><?php $comments->title(); ?></a></div>
<div class="comment-content">
<?php $comments->content(); ?>
</div>
<div class="comment-action hidden-by-mouse">
<?php if('approved' == $comments->status): ?>
<span class="weak"><?php _e('通过'); ?></span>
<?php else: ?>
<a href="<?php $security->index('/action/comments-edit?do=approved&coid=' . $comments->coid); ?>" class="operate-approved"><?php _e('通过'); ?></a>
<?php endif; ?>
<?php if('waiting' == $comments->status): ?>
<span class="weak"><?php _e('待审核'); ?></span>
<?php else: ?>
<a href="<?php $security->index('/action/comments-edit?do=waiting&coid=' . $comments->coid); ?>" class="operate-waiting"><?php _e('待审核'); ?></a>
<?php endif; ?>
<?php if('spam' == $comments->status): ?>
<span class="weak"><?php _e('垃圾'); ?></span>
<?php else: ?>
<a href="<?php $security->index('/action/comments-edit?do=spam&coid=' . $comments->coid); ?>" class="operate-spam"><?php _e('垃圾'); ?></a>
<?php endif; ?>
<a href="#<?php $comments->theId(); ?>" rel="<?php $security->index('/action/comments-edit?do=edit&coid=' . $comments->coid); ?>" class="operate-edit"><?php _e('编辑'); ?></a>
<?php if('approved' == $comments->status && 'comment' == $comments->type): ?>
<a href="#<?php $comments->theId(); ?>" rel="<?php $security->index('/action/comments-edit?do=reply&coid=' . $comments->coid); ?>" class="operate-reply"><?php _e('回复'); ?></a>
<?php endif; ?>
<a lang="<?php _e('你确认要删除%s的评论吗?', htmlspecialchars($comments->author)); ?>" href="<?php $security->index('/action/comments-edit?do=delete&coid=' . $comments->coid); ?>" class="operate-delete"><?php _e('删除'); ?></a>
</div>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="4" class="none"><?php _e('没有评论') ?></td>
</tr>
<?php endif; ?>
</tbody>
</table><!-- end .typecho-list-table -->
<?php if(isset($request->cid)): ?>
<input type="hidden" value="<?php echo $request->filter('html')->cid; ?>" name="cid" />
<?php endif; ?>
</form><!-- end .operate-form -->
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox" class="typecho-table-select-all" /></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a href="<?php $security->index('/action/comments-edit?do=approved'); ?>"><?php _e('通过'); ?></a></li>
<li><a href="<?php $security->index('/action/comments-edit?do=waiting'); ?>"><?php _e('待审核'); ?></a></li>
<li><a href="<?php $security->index('/action/comments-edit?do=spam'); ?>"><?php _e('标记垃圾'); ?></a></li>
<li><a lang="<?php _e('你确认要删除这些评论吗?'); ?>" href="<?php $security->index('/action/comments-edit?do=delete'); ?>"><?php _e('删除'); ?></a></li>
</ul>
<?php if('spam' == $request->get('status')): ?>
<button lang="<?php _e('你确认要删除所有垃圾评论吗?'); ?>" class="btn btn-s btn-warn btn-operate" href="<?php $security->index('/action/comments-edit?do=delete-spam'); ?>"><?php _e('删除所有垃圾评论'); ?></button>
<?php endif; ?>
</div>
</div>
<?php if($comments->have()): ?>
<ul class="typecho-pager">
<?php $comments->pageNav(); ?>
</ul>
<?php endif; ?>
</form>
</div><!-- end .typecho-list -->
</div><!-- end .typecho-page-main -->
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
?>
<script type="text/javascript">
$(document).ready(function () {
// 记住滚动条
function rememberScroll () {
$(window).bind('beforeunload', function () {
$.cookie('__typecho_comments_scroll', $('body').scrollTop());
});
}
// 自动滚动
(function () {
var scroll = $.cookie('__typecho_comments_scroll');
if (scroll) {
$.cookie('__typecho_comments_scroll', null);
$('html, body').scrollTop(scroll);
}
})();
$('.operate-delete').click(function () {
var t = $(this), href = t.attr('href'), tr = t.parents('tr');
if (confirm(t.attr('lang'))) {
tr.fadeOut(function () {
rememberScroll();
window.location.href = href;
});
}
return false;
});
$('.operate-approved, .operate-waiting, .operate-spam').click(function () {
rememberScroll();
window.location.href = $(this).attr('href');
return false;
});
$('.operate-reply').click(function () {
var td = $(this).parents('td'), t = $(this);
if ($('.comment-reply', td).length > 0) {
$('.comment-reply').remove();
} else {
var form = $('<form method="post" action="'
+ t.attr('rel') + '" class="comment-reply">'
+ '<p><label for="text" class="sr-only"><?php _e('内容'); ?></label><textarea id="text" name="text" class="w-90 mono" rows="3"></textarea></p>'
+ '<p><button type="submit" class="btn btn-s primary"><?php _e('回复'); ?></button> <button type="button" class="btn btn-s cancel"><?php _e('取消'); ?></button></p>'
+ '</form>').insertBefore($('.comment-action', td));
$('.cancel', form).click(function () {
$(this).parents('.comment-reply').remove();
});
var textarea = $('textarea', form).focus();
form.submit(function () {
var t = $(this), tr = t.parents('tr'),
reply = $('<div class="comment-reply-content"></div>').insertAfter($('.comment-content', tr));
var html = DOMPurify.sanitize(textarea.val(), {USE_PROFILES: {html: true}});
reply.html('<p>' + html + '</p>');
$.post(t.attr('action'), t.serialize(), function (o) {
var html = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
reply.html(html)
.effect('highlight');
}, 'json');
t.remove();
return false;
});
}
return false;
});
$('.operate-edit').click(function () {
var tr = $(this).parents('tr'), t = $(this), id = tr.attr('id'), comment = tr.data('comment');
tr.hide();
var edit = $('<tr class="comment-edit"><td> </td>'
+ '<td colspan="2" valign="top"><form method="post" action="'
+ t.attr('rel') + '" class="comment-edit-info">'
+ '<p><label for="' + id + '-author"><?php _e('用户名'); ?></label><input class="text-s w-100" id="'
+ id + '-author" name="author" type="text"></p>'
+ '<p><label for="' + id + '-mail"><?php _e('电子邮箱'); ?></label>'
+ '<input class="text-s w-100" type="email" name="mail" id="' + id + '-mail"></p>'
+ '<p><label for="' + id + '-url"><?php _e('个人主页'); ?></label>'
+ '<input class="text-s w-100" type="text" name="url" id="' + id + '-url"></p></form></td>'
+ '<td valign="top"><form method="post" action="'
+ t.attr('rel') + '" class="comment-edit-content"><p><label for="' + id + '-text"><?php _e('内容'); ?></label>'
+ '<textarea name="text" id="' + id + '-text" rows="6" class="w-90 mono"></textarea></p>'
+ '<p><button type="submit" class="btn btn-s primary"><?php _e('提交'); ?></button> '
+ '<button type="button" class="btn btn-s cancel"><?php _e('取消'); ?></button></p></form></td></tr>')
.data('id', id).data('comment', comment).insertAfter(tr);
$('input[name=author]', edit).val(comment.author);
$('input[name=mail]', edit).val(comment.mail);
$('input[name=url]', edit).val(comment.url);
$('textarea[name=text]', edit).val(comment.text).focus();
$('.cancel', edit).click(function () {
var tr = $(this).parents('tr');
$('#' + tr.data('id')).show();
tr.remove();
});
$('form', edit).submit(function () {
var t = $(this), tr = t.parents('tr'),
oldTr = $('#' + tr.data('id')),
comment = oldTr.data('comment');
$('form', tr).each(function () {
var items = $(this).serializeArray();
for (var i = 0; i < items.length; i ++) {
var item = items[i];
comment[item.name] = item.value;
}
});
var unsafeHTML = '<strong class="comment-author">'
+ (comment.url ? '<a target="_blank" href="' + comment.url + '">'
+ comment.author + '</a>' : comment.author) + '</strong>'
+ ('comment' != comment.type ? '<small><?php _e('引用'); ?></small>' : '')
+ (comment.mail ? '<br /><span><a href="mailto:' + comment.mail + '">'
+ comment.mail + '</a></span>' : '')
+ (comment.ip ? '<br /><span>' + comment.ip + '</span>' : '');
var html = DOMPurify.sanitize(unsafeHTML, {USE_PROFILES: {html: true}});
var content = DOMPurify.sanitize(comment.text, {USE_PROFILES: {html: true}});
$('.comment-meta', oldTr).html(html)
.effect('highlight');
$('.comment-content', oldTr).html('<p>' + content + '</p>');
oldTr.data('comment', comment);
$.post(t.attr('action'), comment, function (o) {
var content = DOMPurify.sanitize(o.comment.content, {USE_PROFILES: {html: true}});
$('.comment-content', oldTr).html('<p>' + content + '</p>')
.effect('highlight');
}, 'json');
oldTr.show();
tr.remove();
return false;
});
return false;
});
});
</script>
<?php
include 'footer.php';
?>

137
admin/manage-medias.php Executable file
View File

@@ -0,0 +1,137 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
$attachments = \Widget\Contents\Attachment\Admin::alloc();
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12">
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些文件吗?'); ?>"
href="<?php $security->index('/action/contents-attachment-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
</ul>
<button class="btn btn-s btn-warn btn-operate"
href="<?php $security->index('/action/contents-attachment-edit?do=clear'); ?>"
lang="<?php _e('您确认要清理未归档的文件吗?'); ?>"><?php _e('清理未归档文件'); ?></button>
</div>
</div>
<div class="search" role="search">
<?php if ('' != $request->keywords): ?>
<a href="<?php $options->adminUrl('manage-medias.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo $request->filter('html')->keywords; ?>"<?php if ('' == $request->keywords): ?> onclick="value='';name='keywords';" <?php else: ?> name="keywords"<?php endif; ?>/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
<form method="post" name="manage_medias" class="operate-form">
<table class="typecho-list-table draggable">
<colgroup>
<col width="3%" class="kit-hidden-mb"/>
<col width="6%" class="kit-hidden-mb"/>
<col width="30%"/>
<col width="" class="kit-hidden-mb"/>
<col width="30%" class="kit-hidden-mb"/>
<col width="16%"/>
</colgroup>
<thead>
<tr>
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"></th>
<th><?php _e('文件名'); ?></th>
<th class="kit-hidden-mb"><?php _e('上传者'); ?></th>
<th class="kit-hidden-mb"><?php _e('所属文章'); ?></th>
<th><?php _e('发布日期'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($attachments->have()): ?>
<?php while ($attachments->next()): ?>
<?php $mime = \Typecho\Common::mimeIconType($attachments->attachment->mime); ?>
<tr id="<?php $attachments->theId(); ?>">
<td class="kit-hidden-mb"><input type="checkbox"
value="<?php $attachments->cid(); ?>"
name="cid[]"/></td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-comments.php?cid=' . $attachments->cid); ?>"
class="balloon-button size-<?php echo \Typecho\Common::splitByCount($attachments->commentsNum, 1, 10, 20, 50, 100); ?>"><?php $attachments->commentsNum(); ?></a>
</td>
<td>
<i class="mime-<?php echo $mime; ?>"></i>
<a href="<?php $options->adminUrl('media.php?cid=' . $attachments->cid); ?>"><?php $attachments->title(); ?></a>
<a href="<?php $attachments->permalink(); ?>"
title="<?php _e('浏览 %s', $attachments->title); ?>"><i
class="i-exlink"></i></a>
</td>
<td class="kit-hidden-mb"><?php $attachments->author(); ?></td>
<td class="kit-hidden-mb">
<?php if ($attachments->parentPost->cid): ?>
<a href="<?php $options->adminUrl('write-' . (0 === strpos($attachments->parentPost->type, 'post') ? 'post' : 'page') . '.php?cid=' . $attachments->parentPost->cid); ?>"><?php $attachments->parentPost->title(); ?></a>
<?php else: ?>
<span class="description"><?php _e('未归档'); ?></span>
<?php endif; ?>
</td>
<td><?php $attachments->dateWord(); ?></td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="6" class="none"><?php _e('没有任何文件'); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table><!-- end .typecho-list-table -->
</form><!-- end .operate-form -->
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些文件吗?'); ?>"
href="<?php $security->index('/action/contents-attachment-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
</ul>
</div>
<button class="btn btn-s btn-warn btn-operate"
href="<?php $security->index('/action/contents-attachment-edit?do=clear'); ?>"
lang="<?php _e('您确认要清理未归档的文件吗?'); ?>"><?php _e('清理未归档文件'); ?></button>
</div>
<?php if ($attachments->have()): ?>
<ul class="typecho-pager">
<?php $attachments->pageNav(); ?>
</ul>
<?php endif; ?>
</form>
</div>
</div><!-- end .typecho-page-main -->
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
include 'footer.php';
?>

160
admin/manage-pages.php Executable file
View File

@@ -0,0 +1,160 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
$pages = \Widget\Contents\Page\Admin::alloc();
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 typecho-list">
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些页面吗?'); ?>"
href="<?php $security->index('/action/contents-page-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-page-edit?do=mark&status=publish'); ?>"><?php _e('标记为<strong>%s</strong>', _t('公开')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-page-edit?do=mark&status=hidden'); ?>"><?php _e('标记为<strong>%s</strong>', _t('隐藏')); ?></a>
</li>
</ul>
</div>
</div>
<div class="search" role="search">
<?php $pages->backLink(); ?>
<?php if ('' != $request->keywords): ?>
<a href="<?php $options->adminUrl('manage-pages.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo $request->filter('html')->keywords; ?>" name="keywords"/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
<form method="post" name="manage_pages" class="operate-form">
<table class="typecho-list-table">
<colgroup>
<col width="3%" class="kit-hidden-mb"/>
<col width="6%" class="kit-hidden-mb"/>
<col width="42%"/>
<col width="18%"/>
<col width="" class="kit-hidden-mb"/>
<col width="16%"/>
</colgroup>
<thead>
<tr class="nodrag">
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"></th>
<th><?php _e('标题'); ?></th>
<th><?php _e('子页面'); ?></th>
<th class="kit-hidden-mb"><?php _e('作者'); ?></th>
<th><?php _e('日期'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($pages->have()): ?>
<?php while ($pages->next()): ?>
<tr id="<?php $pages->theId(); ?>">
<td class="kit-hidden-mb"><input type="checkbox" value="<?php $pages->cid(); ?>"
name="cid[]"/></td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-comments.php?cid=' . $pages->cid); ?>"
class="balloon-button size-<?php echo \Typecho\Common::splitByCount($pages->commentsNum, 1, 10, 20, 50, 100); ?>"
title="<?php $pages->commentsNum(); ?> <?php _e('评论'); ?>"><?php $pages->commentsNum(); ?></a>
</td>
<td>
<a href="<?php $options->adminUrl('write-page.php?cid=' . $pages->cid); ?>"><?php $pages->title(); ?></a>
<?php
if ('page_draft' == $pages->type) {
echo '<em class="status">' . _t('草稿') . '</em>';
} elseif ($pages->revision) {
echo '<em class="status">' . _t('有修订版') . '</em>';
}
if ('hidden' == $pages->status) {
echo '<em class="status">' . _t('隐藏') . '</em>';
}
?>
<a href="<?php $options->adminUrl('write-page.php?cid=' . $pages->cid); ?>"
title="<?php _e('编辑 %s', htmlspecialchars($pages->title)); ?>"><i
class="i-edit"></i></a>
<?php if ('page_draft' != $pages->type): ?>
<a href="<?php $pages->permalink(); ?>"
title="<?php _e('浏览 %s', htmlspecialchars($pages->title)); ?>"><i
class="i-exlink"></i></a>
<?php endif; ?>
</td>
<td>
<?php if (count($pages->children) > 0): ?>
<a href="<?php $options->adminUrl('manage-pages.php?parent=' . $pages->cid); ?>"><?php echo _n('一个页面', '%d个页面', count($pages->children)); ?></a>
<?php else: ?>
<a href="<?php $options->adminUrl('write-page.php?parent=' . $pages->cid); ?>"><?php echo _e('新增'); ?></a>
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><?php $pages->author(); ?></td>
<td>
<?php if ('page_draft' == $pages->type || $pages->revision): ?>
<span class="description">
<?php $modifyDate = new \Typecho\Date($pages->revision ? $pages->revision['modified'] : $pages->modified); ?>
<?php _e('保存于 %s', $modifyDate->word()); ?>
</span>
<?php else: ?>
<?php $pages->dateWord(); ?>
<?php endif; ?>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="6" class="none"><?php _e('没有任何页面'); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</form><!-- end .operate-form -->
</div><!-- end .typecho-list -->
</div><!-- end .typecho-page-main -->
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
?>
<?php if (!$request->is('keywords')): ?>
<script type="text/javascript">
(function () {
$(document).ready(function () {
var table = $('.typecho-list-table').tableDnD({
onDrop: function () {
var ids = [];
$('input[type=checkbox]', table).each(function () {
ids.push($(this).val());
});
$.post('<?php $security->index('/action/contents-page-edit?do=sort'); ?>',
$.param({cid: ids}));
}
});
});
})();
</script>
<?php endif; ?>
<?php include 'footer.php'; ?>

252
admin/manage-posts.php Executable file
View File

@@ -0,0 +1,252 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
$posts = \Widget\Contents\Post\Admin::alloc();
$isAllPosts = ('on' == $request->get('__typecho_all_posts') || 'on' == \Typecho\Cookie::get('__typecho_all_posts'));
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 typecho-list">
<div class="typecho-list-operate">
<ul class="typecho-option-tabs">
<li<?php if (!isset($request->status) || 'all' == $request->get('status')): ?> class="current"<?php endif; ?>>
<a href="<?php $options->adminUrl('manage-posts.php'
. (isset($request->uid) ? '?uid=' . $request->filter('encode')->uid : '')); ?>"><?php _e('可用'); ?></a>
</li>
<li<?php if ('waiting' == $request->get('status')): ?> class="current"<?php endif; ?>><a
href="<?php $options->adminUrl('manage-posts.php?status=waiting'
. (isset($request->uid) ? '&uid=' . $request->filter('encode')->uid : '')); ?>"><?php _e('待审核'); ?>
<?php if (!$isAllPosts && $stat->myWaitingPostsNum > 0 && !isset($request->uid)): ?>
<span class="balloon"><?php $stat->myWaitingPostsNum(); ?></span>
<?php elseif ($isAllPosts && $stat->waitingPostsNum > 0 && !isset($request->uid)): ?>
<span class="balloon"><?php $stat->waitingPostsNum(); ?></span>
<?php elseif (isset($request->uid) && $stat->currentWaitingPostsNum > 0): ?>
<span class="balloon"><?php $stat->currentWaitingPostsNum(); ?></span>
<?php endif; ?>
</a></li>
<li<?php if ('draft' == $request->get('status')): ?> class="current"<?php endif; ?>><a
href="<?php $options->adminUrl('manage-posts.php?status=draft'
. (isset($request->uid) ? '&uid=' . $request->filter('encode')->uid : '')); ?>"><?php _e('草稿'); ?>
<?php if (!$isAllPosts && $stat->myDraftPostsNum > 0 && !isset($request->uid)): ?>
<span class="balloon"><?php $stat->myDraftPostsNum(); ?></span>
<?php elseif ($isAllPosts && $stat->draftPostsNum > 0 && !isset($request->uid)): ?>
<span class="balloon"><?php $stat->draftPostsNum(); ?></span>
<?php elseif (isset($request->uid) && $stat->currentDraftPostsNum > 0): ?>
<span class="balloon"><?php $stat->currentDraftPostsNum(); ?></span>
<?php endif; ?>
</a></li>
</ul>
<?php if ($user->pass('editor', true) && !isset($request->uid)): ?>
<ul class="typecho-option-tabs">
<li class="<?php if ($isAllPosts): ?> current<?php endif; ?>"><a
href="<?php echo $request->makeUriByRequest('__typecho_all_posts=on&page=1'); ?>"><?php _e('所有'); ?></a>
</li>
<li class="<?php if (!$isAllPosts): ?> current<?php endif; ?>"><a
href="<?php echo $request->makeUriByRequest('__typecho_all_posts=off&page=1'); ?>"><?php _e('我的'); ?></a>
</li>
</ul>
<?php endif; ?>
</div>
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些文章吗?'); ?>"
href="<?php $security->index('/action/contents-post-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
<?php if ($user->pass('editor', true)): ?>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=publish'); ?>"><?php _e('标记为<strong>%s</strong>', _t('公开')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=waiting'); ?>"><?php _e('标记为<strong>%s</strong>', _t('待审核')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=hidden'); ?>"><?php _e('标记为<strong>%s</strong>', _t('隐藏')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=private'); ?>"><?php _e('标记为<strong>%s</strong>', _t('私密')); ?></a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
<div class="search" role="search">
<?php if ('' != $request->keywords || '' != $request->category): ?>
<a href="<?php $options->adminUrl('manage-posts.php'
. (isset($request->status) || isset($request->uid) ? '?' .
(isset($request->status) ? 'status=' . $request->filter('encode')->status : '') .
(isset($request->uid) ? (isset($request->status) ? '&' : '') . 'uid=' . $request->filter('encode')->uid : '') : '')); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo $request->filter('html')->keywords; ?>" name="keywords"/>
<select name="category">
<option value=""><?php _e('所有分类'); ?></option>
<?php \Widget\Metas\Category\Rows::alloc()->to($category); ?>
<?php while ($category->next()): ?>
<option
value="<?php $category->mid(); ?>"<?php if ($request->get('category') == $category->mid): ?> selected="true"<?php endif; ?>><?php $category->name(); ?></option>
<?php endwhile; ?>
</select>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
<?php if (isset($request->uid)): ?>
<input type="hidden" value="<?php echo $request->filter('html')->uid; ?>"
name="uid"/>
<?php endif; ?>
<?php if (isset($request->status)): ?>
<input type="hidden" value="<?php echo $request->filter('html')->status; ?>"
name="status"/>
<?php endif; ?>
</div>
</form>
<form method="post" name="manage_posts" class="operate-form">
<table class="typecho-list-table">
<colgroup>
<col width="3%" class="kit-hidden-mb"/>
<col width="6%" class="kit-hidden-mb"/>
<col width="45%"/>
<col width="" class="kit-hidden-mb"/>
<col width="18%" class="kit-hidden-mb"/>
<col width="16%"/>
</colgroup>
<thead>
<tr>
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"></th>
<th><?php _e('标题'); ?></th>
<th class="kit-hidden-mb"><?php _e('作者'); ?></th>
<th class="kit-hidden-mb"><?php _e('分类'); ?></th>
<th><?php _e('日期'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($posts->have()): ?>
<?php while ($posts->next()): ?>
<tr id="<?php $posts->theId(); ?>">
<td class="kit-hidden-mb"><input type="checkbox" value="<?php $posts->cid(); ?>"
name="cid[]"/></td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-comments.php?cid=' . ($posts->parentId ? $posts->parentId : $posts->cid)); ?>"
class="balloon-button size-<?php echo \Typecho\Common::splitByCount($posts->commentsNum, 1, 10, 20, 50, 100); ?>"
title="<?php $posts->commentsNum(); ?> <?php _e('评论'); ?>"><?php $posts->commentsNum(); ?></a>
</td>
<td>
<a href="<?php $options->adminUrl('write-post.php?cid=' . $posts->cid); ?>"><?php $posts->title(); ?></a>
<?php
if ('post_draft' == $posts->type) {
echo '<em class="status">' . _t('草稿') . '</em>';
} elseif ($posts->revision) {
echo '<em class="status">' . _t('有修订版') . '</em>';
}
if ('hidden' == $posts->status) {
echo '<em class="status">' . _t('隐藏') . '</em>';
} elseif ('waiting' == $posts->status) {
echo '<em class="status">' . _t('待审核') . '</em>';
} elseif ('private' == $posts->status) {
echo '<em class="status">' . _t('私密') . '</em>';
} elseif ($posts->password) {
echo '<em class="status">' . _t('密码保护') . '</em>';
}
?>
<a href="<?php $options->adminUrl('write-post.php?cid=' . $posts->cid); ?>"
title="<?php _e('编辑 %s', htmlspecialchars($posts->title)); ?>"><i
class="i-edit"></i></a>
<?php if ('post_draft' != $posts->type): ?>
<a href="<?php $posts->permalink(); ?>"
title="<?php _e('浏览 %s', htmlspecialchars($posts->title)); ?>"><i
class="i-exlink"></i></a>
<?php endif; ?>
</td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $posts->author->uid); ?>"><?php $posts->author(); ?></a>
</td>
<td class="kit-hidden-mb"><?php foreach($posts->categories as $index => $category): ?><!--
--><?php echo ($index > 0 ? ', ' : '') . '<a href="';
$options->adminUrl('manage-posts.php?category=' . $category['mid']
. (isset($request->uid) ? '&uid=' . $request->filter('encode')->uid : '')
. (isset($request->status) ? '&status=' . $request->filter('encode')->status : ''));
echo '">' . $category['name'] . '</a>'; ?><!--
--><?php endforeach; ?>
</td>
<td>
<?php if ('post_draft' == $posts->type || $posts->revision): ?>
<span class="description">
<?php $modifyDate = new \Typecho\Date($posts->revision ? $posts->revision['modified'] : $posts->modified); ?>
<?php _e('保存于 %s', $modifyDate->word()); ?>
</span>
<?php else: ?>
<?php $posts->dateWord(); ?>
<?php endif; ?>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="6" class="none"><?php _e('没有任何文章'); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</form><!-- end .operate-form -->
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些文章吗?'); ?>"
href="<?php $security->index('/action/contents-post-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
<?php if ($user->pass('editor', true)): ?>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=publish'); ?>"><?php _e('标记为<strong>%s</strong>', _t('公开')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=waiting'); ?>"><?php _e('标记为<strong>%s</strong>', _t('待审核')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=hidden'); ?>"><?php _e('标记为<strong>%s</strong>', _t('隐藏')); ?></a>
</li>
<li>
<a href="<?php $security->index('/action/contents-post-edit?do=mark&status=private'); ?>"><?php _e('标记为<strong>%s</strong>', _t('私密')); ?></a>
</li>
<?php endif; ?>
</ul>
</div>
</div>
<?php if ($posts->have()): ?>
<ul class="typecho-pager">
<?php $posts->pageNav(); ?>
</ul>
<?php endif; ?>
</form>
</div><!-- end .typecho-list -->
</div><!-- end .typecho-page-main -->
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
include 'footer.php';
?>

104
admin/manage-tags.php Executable file
View File

@@ -0,0 +1,104 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
\Widget\Metas\Tag\Admin::alloc()->to($tags);
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main manage-metas">
<div class="col-mb-12 col-tb-8" role="main">
<form method="post" name="manage_tags" class="operate-form">
<div class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些标签吗?'); ?>"
href="<?php $security->index('/action/metas-tag-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
<li><a lang="<?php _e('刷新标签可能需要等待较长时间, 你确认要刷新这些标签吗?'); ?>"
href="<?php $security->index('/action/metas-tag-edit?do=refresh'); ?>"><?php _e('刷新'); ?></a>
</li>
<li class="multiline">
<button type="button" class="btn btn-s merge"
rel="<?php $security->index('/action/metas-tag-edit?do=merge'); ?>"><?php _e('合并到'); ?></button>
<input type="text" name="merge" class="text-s"/>
</li>
</ul>
</div>
</div>
</div>
<?php if ($tags->have()): ?>
<ul class="typecho-list-notable tag-list">
<?php while ($tags->next()): ?>
<li class="size-<?php $tags->split(5, 10, 20, 30); ?>" id="<?php $tags->theId(); ?>">
<input type="checkbox" value="<?php $tags->mid(); ?>" name="mid[]"/>
<span
rel="<?php echo $request->makeUriByRequest('mid=' . $tags->mid); ?>"><?php $tags->name(); ?></span>
<a class="tag-edit-link"
href="<?php echo $request->makeUriByRequest('mid=' . $tags->mid); ?>"><i
class="i-edit"></i></a>
</li>
<?php endwhile; ?>
</ul>
<?php else: ?>
<ul class="tag-list">
<li class="none"><?php _e('没有任何标签'); ?></li>
</ul>
<?php endif; ?>
<input type="hidden" name="do" value="delete"/>
</form>
</div>
<div class="col-mb-12 col-tb-4" role="form">
<?php \Widget\Metas\Tag\Edit::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
?>
<script type="text/javascript">
(function () {
$(document).ready(function () {
$('.typecho-list-notable').tableSelectable({
checkEl: 'input[type=checkbox]',
rowEl: 'li',
selectAllEl: '.typecho-table-select-all',
actionEl: '.dropdown-menu a'
});
$('.btn-drop').dropdownMenu({
btnEl: '.dropdown-toggle',
menuEl: '.dropdown-menu'
});
$('.dropdown-menu button.merge').click(function () {
var btn = $(this);
btn.parents('form').attr('action', btn.attr('rel')).submit();
});
<?php if (isset($request->mid)): ?>
$('.typecho-mini-panel').effect('highlight', '#AACB36');
<?php endif; ?>
});
})();
</script>
<?php include 'footer.php'; ?>

133
admin/manage-users.php Executable file
View File

@@ -0,0 +1,133 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$users = \Widget\Users\Admin::alloc();
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 typecho-list">
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些用户吗?'); ?>"
href="<?php $security->index('/action/users-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
</ul>
</div>
</div>
<div class="search" role="search">
<?php if ('' != $request->keywords): ?>
<a href="<?php $options->adminUrl('manage-users.php'); ?>"><?php _e('&laquo; 取消筛选'); ?></a>
<?php endif; ?>
<input type="text" class="text-s" placeholder="<?php _e('请输入关键字'); ?>"
value="<?php echo $request->filter('html')->keywords; ?>" name="keywords"/>
<button type="submit" class="btn btn-s"><?php _e('筛选'); ?></button>
</div>
</form>
<form method="post" name="manage_users" class="operate-form">
<table class="typecho-list-table">
<colgroup>
<col width="3%" class="kit-hidden-mb"/>
<col width="6%" class="kit-hidden-mb"/>
<col width="30%"/>
<col width="" class="kit-hidden-mb"/>
<col width="25%" class="kit-hidden-mb"/>
<col width="15%"/>
</colgroup>
<thead>
<tr>
<th class="kit-hidden-mb"></th>
<th class="kit-hidden-mb"></th>
<th><?php _e('用户名'); ?></th>
<th class="kit-hidden-mb"><?php _e('昵称'); ?></th>
<th class="kit-hidden-mb"><?php _e('电子邮件'); ?></th>
<th><?php _e('用户组'); ?></th>
</tr>
</thead>
<tbody>
<?php while ($users->next()): ?>
<tr id="user-<?php $users->uid(); ?>">
<td class="kit-hidden-mb"><input type="checkbox" value="<?php $users->uid(); ?>"
name="uid[]"/></td>
<td class="kit-hidden-mb"><a
href="<?php $options->adminUrl('manage-posts.php?__typecho_all_posts=off&uid=' . $users->uid); ?>"
class="balloon-button left size-<?php echo \Typecho\Common::splitByCount($users->postsNum, 1, 10, 20, 50, 100); ?>"><?php $users->postsNum(); ?></a>
</td>
<td>
<a href="<?php $options->adminUrl('user.php?uid=' . $users->uid); ?>"><?php $users->name(); ?></a>
<a href="<?php $users->permalink(); ?>"
title="<?php _e('浏览 %s', $users->screenName); ?>"><i
class="i-exlink"></i></a>
</td>
<td class="kit-hidden-mb"><?php $users->screenName(); ?></td>
<td class="kit-hidden-mb"><?php if ($users->mail): ?><a
href="mailto:<?php $users->mail(); ?>"><?php $users->mail(); ?></a><?php else: _e('暂无'); endif; ?>
</td>
<td><?php switch ($users->group) {
case 'administrator':
_e('管理员');
break;
case 'editor':
_e('编辑');
break;
case 'contributor':
_e('贡献者');
break;
case 'subscriber':
_e('关注者');
break;
case 'visitor':
_e('访问者');
break;
default:
break;
} ?></td>
</tr>
<?php endwhile; ?>
</tbody>
</table><!-- end .typecho-list-table -->
</form><!-- end .operate-form -->
<form method="get" class="typecho-list-operate">
<div class="operate">
<label><i class="sr-only"><?php _e('全选'); ?></i><input type="checkbox"
class="typecho-table-select-all"/></label>
<div class="btn-group btn-drop">
<button class="btn dropdown-toggle btn-s" type="button"><i
class="sr-only"><?php _e('操作'); ?></i><?php _e('选中项'); ?> <i
class="i-caret-down"></i></button>
<ul class="dropdown-menu">
<li><a lang="<?php _e('你确认要删除这些用户吗?'); ?>"
href="<?php $security->index('/action/users-edit?do=delete'); ?>"><?php _e('删除'); ?></a>
</li>
</ul>
</div>
</div>
<?php if ($users->have()): ?>
<ul class="typecho-pager">
<?php $users->pageNav(); ?>
</ul>
<?php endif; ?>
</form>
</div><!-- end .typecho-list -->
</div><!-- end .typecho-page-main -->
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'table-js.php';
include 'footer.php';
?>

80
admin/media.php Executable file
View File

@@ -0,0 +1,80 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
\Widget\Contents\Attachment\Edit::alloc()->prepare()->to($attachment);
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-8" role="main">
<?php if ($attachment->attachment->isImage): ?>
<p><img src="<?php $attachment->attachment->url(); ?>"
alt="<?php $attachment->attachment->name(); ?>" class="typecho-attachment-photo"/></p>
<?php endif; ?>
<p>
<?php $mime = \Typecho\Common::mimeIconType($attachment->attachment->mime); ?>
<i class="mime-<?php echo $mime; ?>"></i>
<a href=""><strong><?php $attachment->attachment->name(); ?></strong></a>
<span><?php echo number_format(ceil($attachment->attachment->size / 1024)); ?> Kb</span>
</p>
<p>
<input id="attachment-url" type="text" class="mono w-100"
value="<?php $attachment->attachment->url(); ?>" readonly/>
</p>
<div id="upload-panel" class="p">
<div class="upload-area" data-url="<?php $security->index('/action/upload?do=modify'); ?>">
<?php _e('拖放文件到这里<br>或者 %s选择文件上传%s', '<a href="###" class="upload-file">', '</a>'); ?>
</div>
<ul id="file-list"></ul>
</div>
</div>
<div class="col-mb-12 col-tb-4 edit-media" role="form">
<?php $attachment->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'file-upload-js.php';
?>
<script type="text/javascript">
$(document).ready(function () {
$('#attachment-url').click(function () {
$(this).select();
});
$('.operate-delete').click(function () {
var t = $(this), href = t.attr('href');
if (confirm(t.attr('lang'))) {
window.location.href = href;
}
return false;
});
Typecho.uploadComplete = function (attachment) {
if (attachment.isImage) {
$('.typecho-attachment-photo').attr('src', attachment.url + '?' + Math.random());
}
$('#file-list li').text('<?php _e('文件 %s 已经替换'); ?>'.replace('%s', attachment.title))
.effect('highlight', 1000, function () {
$(this).remove();
});
};
});
</script>
<?php
include 'footer.php';
?>

22
admin/menu.php Executable file
View File

@@ -0,0 +1,22 @@
<?php if (!defined('__TYPECHO_ADMIN__')) exit; ?>
<header class="typecho-head-nav" role="navigation">
<nav>
<details class="menu-bar">
<summary><?php _e('菜单'); ?></summary>
</details>
<menu>
<?php $menu->output(); ?>
<li class="operate">
<?php \Typecho\Plugin::factory('admin/menu.php')->call('navBar'); ?><a title="<?php
if ($user->logged > 0) {
$logged = new \Typecho\Date($user->logged);
_e('最后登录: %s', $logged->word());
}
?>" href="<?php $options->adminUrl('profile.php'); ?>" class="author"><?php $user->screenName(); ?></a><a
class="exit" href="<?php $options->logoutUrl(); ?>"><?php _e('登出'); ?></a><a
href="<?php $options->siteUrl(); ?>"><?php _e('网站'); ?></a>
</li>
</menu>
</nav>
</header>

23
admin/options-discussion.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<?php \Widget\Options\Discussion::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'footer.php';
?>

23
admin/options-general.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<?php \Widget\Options\General::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'footer.php';
?>

24
admin/options-permalink.php Executable file
View File

@@ -0,0 +1,24 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<?php \Widget\Options\Permalink::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
?>
<?php include 'footer.php'; ?>

23
admin/options-plugin.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<?php \Widget\Plugins\Config::alloc()->config()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'footer.php';
?>

37
admin/options-reading.php Executable file
View File

@@ -0,0 +1,37 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-8 col-tb-offset-2">
<?php \Widget\Options\Reading::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
?>
<script>
$('#frontPage-recent,#frontPage-page,#frontPage-file').change(function () {
var t = $(this);
if (t.prop('checked')) {
if ('frontPage-recent' == t.attr('id')) {
$('.front-archive').addClass('hidden');
} else {
$('.front-archive').insertAfter(t.parent()).removeClass('hidden');
}
}
});
</script>
<?php
include 'footer.php';
?>

24
admin/options-theme.php Executable file
View File

@@ -0,0 +1,24 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<?php include 'theme-tabs.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 col-tb-8 col-tb-offset-2" role="form">
<?php \Widget\Themes\Config::alloc()->config()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'footer.php';
?>

9
admin/page-title.php Executable file
View File

@@ -0,0 +1,9 @@
<?php if (!defined('__TYPECHO_ADMIN__')) exit; ?>
<div class="typecho-page-title">
<h2><?php echo $menu->title; ?></h2>
<?php
if (!empty($menu->addLink)) {
echo "<a href=\"{$menu->addLink}\">" . _t("新增") . "</a>";
}
?>
</div>

129
admin/plugins.php Executable file
View File

@@ -0,0 +1,129 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12 typecho-list">
<?php \Widget\Plugins\Rows::allocWithAlias('activated', 'activated=1')->to($activatedPlugins); ?>
<?php if ($activatedPlugins->have() || !empty($activatedPlugins->activatedPlugins)): ?>
<h4 class="typecho-list-table-title"><?php _e('启用的插件'); ?></h4>
<table class="typecho-list-table">
<colgroup>
<col width="25%"/>
<col width="45%"/>
<col width="8%" class="kit-hidden-mb"/>
<col width="10%" class="kit-hidden-mb"/>
<col width=""/>
</colgroup>
<thead>
<tr>
<th><?php _e('名称'); ?></th>
<th><?php _e('描述'); ?></th>
<th class="kit-hidden-mb"><?php _e('版本'); ?></th>
<th class="kit-hidden-mb"><?php _e('作者'); ?></th>
<th><?php _e('操作'); ?></th>
</tr>
</thead>
<tbody>
<?php while ($activatedPlugins->next()): ?>
<tr id="plugin-<?php $activatedPlugins->name(); ?>">
<td><?php $activatedPlugins->title(); ?>
<?php if (!$activatedPlugins->dependence): ?>
<i class="i-delete"
title="<?php _e('%s 无法在此版本的typecho下正常工作', $activatedPlugins->title); ?>"></i>
<?php endif; ?>
</td>
<td><?php $activatedPlugins->description(); ?></td>
<td class="kit-hidden-mb"><?php $activatedPlugins->version(); ?></td>
<td class="kit-hidden-mb"><?php echo empty($activatedPlugins->homepage) ? $activatedPlugins->author : '<a href="' . $activatedPlugins->homepage
. '">' . $activatedPlugins->author . '</a>'; ?></td>
<td>
<?php if ($activatedPlugins->activate || $activatedPlugins->deactivate || $activatedPlugins->config || $activatedPlugins->personalConfig): ?>
<?php if ($activatedPlugins->config): ?>
<a href="<?php $options->adminUrl('options-plugin.php?config=' . $activatedPlugins->name); ?>"><?php _e('设置'); ?></a>
&bull;
<?php endif; ?>
<a lang="<?php _e('你确认要禁用插件 %s 吗?', $activatedPlugins->name); ?>"
href="<?php $security->index('/action/plugins-edit?deactivate=' . $activatedPlugins->name); ?>"><?php _e('禁用'); ?></a>
<?php else: ?>
<span class="important"><?php _e('即插即用'); ?></span>
<?php endif; ?>
</td>
</tr>
<?php endwhile; ?>
<?php if (!empty($activatedPlugins->activatedPlugins)): ?>
<?php foreach ($activatedPlugins->activatedPlugins as $key => $val): ?>
<tr>
<td><?php echo $key; ?></td>
<td colspan="3"><span
class="warning"><?php _e('此插件文件已经损坏或者被不安全移除, 强烈建议你禁用它'); ?></span></td>
<td><a lang="<?php _e('你确认要禁用插件 %s 吗?', $key); ?>"
href="<?php $security->index('/action/plugins-edit?deactivate=' . $key); ?>"><?php _e('禁用'); ?></a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php endif; ?>
<?php \Widget\Plugins\Rows::allocWithAlias('unactivated', 'activated=0')->to($deactivatedPlugins); ?>
<?php if ($deactivatedPlugins->have() || !$activatedPlugins->have()): ?>
<h4 class="typecho-list-table-title"><?php _e('禁用的插件'); ?></h4>
<table class="typecho-list-table deactivate">
<colgroup>
<col width="25%"/>
<col width="45%"/>
<col width="8%" class="kit-hidden-mb"/>
<col width="10%" class="kit-hidden-mb"/>
<col width=""/>
</colgroup>
<thead>
<tr>
<th><?php _e('名称'); ?></th>
<th><?php _e('描述'); ?></th>
<th class="kit-hidden-mb"><?php _e('版本'); ?></th>
<th class="kit-hidden-mb"><?php _e('作者'); ?></th>
<th class="typecho-radius-topright"><?php _e('操作'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($deactivatedPlugins->have()): ?>
<?php while ($deactivatedPlugins->next()): ?>
<tr id="plugin-<?php $deactivatedPlugins->name(); ?>">
<td><?php $deactivatedPlugins->title(); ?></td>
<td><?php $deactivatedPlugins->description(); ?></td>
<td class="kit-hidden-mb"><?php $deactivatedPlugins->version(); ?></td>
<td class="kit-hidden-mb"><?php echo empty($deactivatedPlugins->homepage) ? $deactivatedPlugins->author : '<a href="' . $deactivatedPlugins->homepage
. '">' . $deactivatedPlugins->author . '</a>'; ?></td>
<td>
<a href="<?php $security->index('/action/plugins-edit?activate=' . $deactivatedPlugins->name); ?>"><?php _e('启用'); ?></a>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr>
<td colspan="5"><h6 class="typecho-list-table-title"><?php _e('没有安装插件'); ?></h6>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'footer.php';
?>

27
admin/preview.php Executable file
View File

@@ -0,0 +1,27 @@
<?php
include 'common.php';
/** 获取内容 Widget */
\Widget\Archive::alloc('type=single&checkPermalink=0&preview=1')->to($content);
/** 检测是否存在 */
if (!$content->have()) {
$response->redirect($options->adminUrl);
}
/** 检测权限 */
if (!$user->pass('editor', true) && $content->authorId != $user->uid) {
$response->redirect($options->adminUrl);
}
/** 输出内容 */
$content->render();
?>
<script>
window.onbeforeunload = function () {
if (!!window.parent) {
window.parent.postMessage('cancelPreview', '<?php $options->rootUrl(); ?>');
}
}
</script>

62
admin/profile.php Executable file
View File

@@ -0,0 +1,62 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$stat = \Widget\Stat::alloc();
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main">
<div class="col-mb-12 col-tb-3">
<p><a href="https://gravatar.com/"
title="<?php _e('在 Gravatar 上修改头像'); ?>"><?php echo '<img class="profile-avatar" src="' . \Typecho\Common::gravatarUrl($user->mail, 220, 'X', 'mm', $request->isSecure()) . '" alt="' . $user->screenName . '" />'; ?></a>
</p>
<h2><?php $user->screenName(); ?></h2>
<p><?php $user->name(); ?></p>
<p><?php _e('目前有 <em>%s</em> 篇日志, 并有 <em>%s</em> 条关于你的评论在 <em>%s</em> 个分类中.',
$stat->myPublishedPostsNum, $stat->myPublishedCommentsNum, $stat->categoriesNum); ?></p>
<p><?php
if ($user->logged > 0) {
$logged = new \Typecho\Date($user->logged);
_e('最后登录: %s', $logged->word());
}
?></p>
</div>
<div class="col-mb-12 col-tb-6 col-tb-offset-1 typecho-content-panel" role="form">
<section>
<h3><?php _e('个人资料'); ?></h3>
<?php \Widget\Users\Profile::alloc()->profileForm()->render(); ?>
</section>
<?php if ($user->pass('contributor', true)): ?>
<br>
<section id="writing-option">
<h3><?php _e('撰写设置'); ?></h3>
<?php \Widget\Users\Profile::alloc()->optionsForm()->render(); ?>
</section>
<?php endif; ?>
<br>
<section id="change-password">
<h3><?php _e('密码修改'); ?></h3>
<?php \Widget\Users\Profile::alloc()->passwordForm()->render(); ?>
</section>
<?php \Widget\Users\Profile::alloc()->personalFormList(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
\Typecho\Plugin::factory('admin/profile.php')->call('bottom');
include 'footer.php';
?>

50
admin/register.php Executable file
View File

@@ -0,0 +1,50 @@
<?php
include 'common.php';
if ($user->hasLogin() || !$options->allowRegister) {
$response->redirect($options->siteUrl);
}
$rememberName = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_name', ''));
$rememberMail = htmlspecialchars(\Typecho\Cookie::get('__typecho_remember_mail', ''));
\Typecho\Cookie::delete('__typecho_remember_name');
\Typecho\Cookie::delete('__typecho_remember_mail');
$bodyClass = 'body-100';
include 'header.php';
?>
<div class="typecho-login-wrap">
<div class="typecho-login">
<h1><a href="https://typecho.org" class="i-logo">Typecho</a></h1>
<form action="<?php $options->registerAction(); ?>" method="post" name="register" role="form">
<p>
<label for="name" class="sr-only"><?php _e('用户名'); ?></label>
<input type="text" id="name" name="name" placeholder="<?php _e('用户名'); ?>" value="<?php echo $rememberName; ?>" class="text-l w-100" autofocus />
</p>
<p>
<label for="mail" class="sr-only"><?php _e('Email'); ?></label>
<input type="email" id="mail" name="mail" placeholder="<?php _e('Email'); ?>" value="<?php echo $rememberMail; ?>" class="text-l w-100" />
</p>
<p class="submit">
<button type="submit" class="btn btn-l w-100 primary"><?php _e('注册'); ?></button>
</p>
</form>
<p class="more-link">
<a href="<?php $options->siteUrl(); ?>"><?php _e('返回首页'); ?></a>
&bull;
<a href="<?php $options->adminUrl('login.php'); ?>"><?php _e('用户登录'); ?></a>
</p>
</div>
</div>
<?php
include 'common-js.php';
?>
<script>
$(document).ready(function () {
$('#name').focus();
});
</script>
<?php
include 'footer.php';
?>

19
admin/table-js.php Executable file
View File

@@ -0,0 +1,19 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
<script>
(function () {
$(document).ready(function () {
$('.typecho-list-table').tableSelectable({
checkEl : 'input[type=checkbox]',
rowEl : 'tr',
selectAllEl : '.typecho-table-select-all',
actionEl : '.dropdown-menu a,button.btn-operate'
});
$('.btn-drop').dropdownMenu({
btnEl : '.dropdown-toggle',
menuEl : '.dropdown-menu'
});
});
})();
</script>

48
admin/theme-editor.php Executable file
View File

@@ -0,0 +1,48 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
\Widget\Themes\Files::alloc()->to($files);
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<?php include 'theme-tabs.php'; ?>
<div class="row typecho-page-main typecho-edit-theme" role="main">
<div class="col-mb-12 col-tb-8 col-9 content">
<form method="post" name="theme" id="theme"
action="<?php $security->index('/action/themes-edit'); ?>">
<label for="content" class="sr-only"><?php _e('编辑源码'); ?></label>
<textarea name="content" id="content" class="w-100 mono"
<?php if (!$files->currentIsWriteable()): ?>readonly<?php endif; ?>><?php echo $files->currentContent(); ?></textarea>
<p class="typecho-option typecho-option-submit">
<?php if ($files->currentIsWriteable()): ?>
<input type="hidden" name="theme" value="<?php echo $files->currentTheme(); ?>"/>
<input type="hidden" name="edit" value="<?php echo $files->currentFile(); ?>"/>
<button type="submit" class="btn primary"><?php _e('保存文件'); ?></button>
<?php else: ?>
<em><?php _e('此文件无法写入'); ?></em>
<?php endif; ?>
</p>
</form>
</div>
<ul class="col-mb-12 col-tb-4 col-3">
<li><strong>模板文件</strong></li>
<?php while ($files->next()): ?>
<li<?php if ($files->current): ?> class="current"<?php endif; ?>>
<a href="<?php $options->adminUrl('theme-editor.php?theme=' . $files->currentTheme() . '&file=' . $files->file); ?>"><?php $files->file(); ?></a>
</li>
<?php endwhile; ?>
</ul>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
\Typecho\Plugin::factory('admin/theme-editor.php')->call('bottom', $files);
include 'footer.php';
?>

16
admin/theme-tabs.php Executable file
View File

@@ -0,0 +1,16 @@
<?php if (!defined('__TYPECHO_ADMIN__')) exit; ?>
<ul class="typecho-option-tabs fix-tabs">
<li<?php if ($menu->getCurrentMenuUrl() === 'themes.php'): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('themes.php'); ?>"><?php _e('可以使用的外观'); ?></a></li>
<?php if (\Widget\Themes\Files::isWriteable()): ?>
<li<?php if ($menu->getCurrentMenuUrl() === 'theme-editor.php'): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('theme-editor.php'); ?>">
<?php if (!isset($files) || $options->theme == $files->theme): ?>
<?php _e('编辑当前外观'); ?>
<?php else: ?>
<?php _e('编辑%s外观', ' <cite>' . $files->theme . '</cite> '); ?>
<?php endif; ?>
</a></li>
<?php endif; ?>
<?php if (\Widget\Themes\Config::isExists()): ?>
<li<?php if ($menu->getCurrentMenuUrl() === 'options-theme.php'): ?> class="current"<?php endif; ?>><a href="<?php $options->adminUrl('options-theme.php'); ?>"><?php _e('设置外观'); ?></a></li>
<?php endif; ?>
</ul>

73
admin/themes.php Executable file
View File

@@ -0,0 +1,73 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<?php include 'theme-tabs.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12">
<table class="typecho-list-table typecho-theme-list">
<colgroup>
<col width="35%"/>
<col/>
</colgroup>
<thead>
<th><?php _e('截图'); ?></th>
<th><?php _e('详情'); ?></th>
</thead>
<tbody>
<?php if ($options->missingTheme): ?>
<tr id="theme-<?php $options->missingTheme; ?>" class="current">
<td colspan="2" class="warning">
<p><strong><?php _e('检测到您之前使用的 "%s" 外观文件不存在,您可以重新上传此外观或者启用其他外观。', $options->missingTheme); ?></strong></p>
<ul>
<li><?php _e('重新上传此外观后刷新当前页面,此提示将会消失。'); ?></li>
<li><?php _e('启用新外观后,当前外观的设置数据将被删除。'); ?></li>
</ul>
</td>
</tr>
<?php endif; ?>
<?php \Widget\Themes\Rows::alloc()->to($themes); ?>
<?php while ($themes->next()): ?>
<tr id="theme-<?php $themes->name(); ?>"
class="<?php if ($themes->activated && !$options->missingTheme): ?>current<?php endif; ?>">
<td valign="top"><img src="<?php $themes->screen(); ?>"
alt="<?php $themes->name(); ?>"/></td>
<td valign="top">
<h3><?php '' != $themes->title ? $themes->title() : $themes->name(); ?></h3>
<cite>
<?php if ($themes->author): ?><?php _e('作者'); ?>: <?php if ($themes->homepage): ?><a href="<?php $themes->homepage() ?>"><?php endif; ?><?php $themes->author(); ?><?php if ($themes->homepage): ?></a><?php endif; ?> &nbsp;&nbsp;<?php endif; ?>
<?php if ($themes->version): ?><?php _e('版本'); ?>: <?php $themes->version() ?><?php endif; ?>
</cite>
<p><?php echo nl2br($themes->description); ?></p>
<?php if ($options->theme != $themes->name || $options->missingTheme): ?>
<p>
<?php if (\Widget\Themes\Files::isWriteable()): ?>
<a class="edit"
href="<?php $options->adminUrl('theme-editor.php?theme=' . $themes->name); ?>"><?php _e('编辑'); ?></a> &nbsp;
<?php endif; ?>
<a class="activate"
href="<?php $security->index('/action/themes-edit?change=' . $themes->name); ?>"><?php _e('启用'); ?></a>
</p>
<?php endif; ?>
</td>
</tr>
<?php endwhile; ?>
</tbody>
</table>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'footer.php';
?>

45
admin/upgrade.php Executable file
View File

@@ -0,0 +1,45 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12">
<div id="typecho-welcome">
<form action="<?php echo $security->getTokenUrl(
\Typecho\Router::url('do', ['action' => 'upgrade', 'widget' => 'Upgrade'],
\Typecho\Common::url('index.php', $options->rootUrl))); ?>" method="post">
<h3><?php _e('检测到新版本!'); ?></h3>
<ul>
<li><?php _e('您已经更新了系统程序, 我们还需要执行一些后续步骤来完成升级'); ?></li>
<li><?php _e('此程序将把您的系统从 <strong>%s</strong> 升级到 <strong>%s</strong>', $options->version, \Typecho\Common::VERSION); ?></li>
<li><strong
class="warning"><?php _e('在升级之前强烈建议先<a href="%s">备份您的数据</a>', \Typecho\Common::url('backup.php', $options->adminUrl)); ?></strong>
</li>
</ul>
<p>
<button class="btn primary" type="submit"><?php _e('完成升级 &raquo;'); ?></button>
</p>
</form>
</div>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
?>
<script>
(function () {
if (window.sessionStorage) {
sessionStorage.removeItem('update');
}
})();
</script>
<?php include 'footer.php'; ?>

23
admin/user.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="form">
<div class="col-mb-12 col-tb-6 col-tb-offset-3">
<?php \Widget\Users\Edit::alloc()->form()->render(); ?>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'footer.php';
?>

36
admin/welcome.php Executable file
View File

@@ -0,0 +1,36 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<div class="row typecho-page-main" role="main">
<div class="col-mb-12">
<div id="typecho-welcome" class="message">
<form action="<?php $options->adminUrl(); ?>" method="get">
<h3><?php _e('欢迎您使用 "%s" 管理后台: ', $options->title); ?></h3>
<ol>
<li><a class="operate-delete" href="<?php $options->adminUrl('profile.php#change-password'); ?>"><?php _e('强烈建议更改你的默认密码'); ?></a></li>
<?php if($user->pass('contributor', true)): ?>
<li><a href="<?php $options->adminUrl('write-post.php'); ?>"><?php _e('撰写第一篇日志'); ?></a></li>
<li><a href="<?php $options->siteUrl(); ?>"><?php $user->pass('administrator', true) ? _e('查看我的站点') : _e('查看网站'); ?></a></li>
<?php else: ?>
<li><a href="<?php $options->siteUrl(); ?>"><?php _e('查看网站'); ?></a></li>
<?php endif; ?>
</ol>
<p><button type="submit" class="btn primary"><?php _e('让我直接开始使用吧 &raquo;'); ?></button></p>
</form>
</div>
</div>
</div>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'footer.php';
?>

344
admin/write-js.php Executable file
View File

@@ -0,0 +1,344 @@
<?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
<?php \Typecho\Plugin::factory('admin/write-js.php')->call('write'); ?>
<?php \Widget\Metas\Tag\Cloud::alloc('sort=count&desc=1&limit=200')->to($tags); ?>
<script src="<?php $options->adminStaticUrl('js', 'timepicker.js'); ?>"></script>
<script src="<?php $options->adminStaticUrl('js', 'tokeninput.js'); ?>"></script>
<script>
$(document).ready(function() {
// 日期时间控件
$('#date').mask('9999-99-99 99:99').datetimepicker({
currentText : '<?php _e('现在'); ?>',
prevText : '<?php _e('上一月'); ?>',
nextText : '<?php _e('下一月'); ?>',
monthNames : ['<?php _e('一月'); ?>', '<?php _e('二月'); ?>', '<?php _e('三月'); ?>', '<?php _e('四月'); ?>',
'<?php _e('五月'); ?>', '<?php _e('六月'); ?>', '<?php _e('七月'); ?>', '<?php _e('八月'); ?>',
'<?php _e('九月'); ?>', '<?php _e('十月'); ?>', '<?php _e('十一月'); ?>', '<?php _e('十二月'); ?>'],
dayNames : ['<?php _e('星期日'); ?>', '<?php _e('星期一'); ?>', '<?php _e('星期二'); ?>',
'<?php _e('星期三'); ?>', '<?php _e('星期四'); ?>', '<?php _e('星期五'); ?>', '<?php _e('星期六'); ?>'],
dayNamesShort : ['<?php _e('周日'); ?>', '<?php _e('周一'); ?>', '<?php _e('周二'); ?>', '<?php _e('周三'); ?>',
'<?php _e('周四'); ?>', '<?php _e('周五'); ?>', '<?php _e('周六'); ?>'],
dayNamesMin : ['<?php _e('日'); ?>', '<?php _e('一'); ?>', '<?php _e('二'); ?>', '<?php _e('三'); ?>',
'<?php _e('四'); ?>', '<?php _e('五'); ?>', '<?php _e('六'); ?>'],
closeText : '<?php _e('完成'); ?>',
timeOnlyTitle : '<?php _e('选择时间'); ?>',
timeText : '<?php _e('时间'); ?>',
hourText : '<?php _e('时'); ?>',
amNames : ['<?php _e('上午'); ?>', 'A'],
pmNames : ['<?php _e('下午'); ?>', 'P'],
minuteText : '<?php _e('分'); ?>',
secondText : '<?php _e('秒'); ?>',
dateFormat : 'yy-mm-dd',
timezone : <?php $options->timezone(); ?> / 60,
hour : (new Date()).getHours(),
minute : (new Date()).getMinutes()
});
// 聚焦
$('#title').select();
// text 自动拉伸
Typecho.editorResize('text', '<?php $security->index('/action/ajax?do=editorResize'); ?>');
// tag autocomplete 提示
const tags = $('#tags'), tagsPre = [];
if (tags.length > 0) {
const items = tags.val().split(',');
for (let i = 0; i < items.length; i ++) {
const tag = items[i];
if (!tag) {
continue;
}
tagsPre.push({
id : tag,
tags : tag
});
}
tags.tokenInput(<?php
$data = array();
while ($tags->next()) {
$data[] = array(
'id' => $tags->name,
'tags' => $tags->name
);
}
echo json_encode($data);
?>, {
propertyToSearch: 'tags',
tokenValue : 'tags',
searchDelay : 0,
preventDuplicates : true,
animateDropdown : false,
hintText : '<?php _e('请输入标签名'); ?>',
noResultsText : '<?php _e('此标签不存在, 按回车创建'); ?>',
prePopulate : tagsPre,
onResult : function (result, query, val) {
// remove special chars
val = val.replace(/<|>|&|"|'/g, '');
if (!query) {
return result;
}
if (!result) {
result = [];
}
if (!result[0] || result[0]['id'] !== query) {
result.unshift({
id : val,
tags : val
});
}
return result.slice(0, 5);
}
});
// tag autocomplete 提示宽度设置
$('#token-input-tags').focus(function() {
const t = $('.token-input-dropdown'),
offset = t.outerWidth() - t.width();
t.width($('.token-input-list').outerWidth() - offset);
});
}
// 缩略名自适应宽度
const slug = $('#slug');
if (slug.length > 0) {
const wrap = $('<div />').css({
'position' : 'relative',
'display' : 'inline-block'
}),
justifySlug = $('<pre />').css({
'display' : 'block',
'visibility': 'hidden',
'height' : slug.height(),
'padding' : '0 2px',
'margin' : 0
}).insertAfter(slug.wrap(wrap).css({
'left' : 0,
'top' : 0,
'minWidth' : '5px',
'position' : 'absolute',
'width' : '100%'
}));
function justifySlugWidth() {
const val = slug.val();
justifySlug.text(val.length > 0 ? val : ' ');
}
slug.bind('input propertychange', justifySlugWidth);
justifySlugWidth();
}
// 处理保存文章的逻辑
const form = $('form[name=write_post],form[name=write_page]'),
idInput = $('input[name=cid]'),
draft = $('input[name=draft]'),
btnPreview = $('#btn-preview'),
autoSave = $('<span id="auto-save-message"></span>').prependTo('.left');
let cid = idInput.val(),
draftId = draft.length > 0 ? draft.val() : 0,
changed = false,
written = false,
lastSaveTime = null;
form.on('write', function () {
written = true;
form.trigger('datachange');
});
form.on('change', function () {
if (written) {
form.trigger('datachange');
}
});
$('button[name=do]').click(function () {
$('input[name=do]').val($(this).val());
});
// 自动检测离开页
$(window).bind('beforeunload', function () {
if (changed && !form.hasClass('submitting')) {
return '<?php _e('内容已经改变尚未保存, 您确认要离开此页面吗?'); ?>';
}
});
// 发送保存请求
Typecho.savePost = function(cb) {
if (!changed) {
cb && cb();
return;
}
const callback = function (o) {
lastSaveTime = o.time;
cid = o.cid;
draftId = o.draftId;
idInput.val(cid);
autoSave.text('<?php _e('已保存'); ?>' + ' (' + o.time + ')').effect('highlight', 1000);
cb && cb();
};
changed = false;
autoSave.text('<?php _e('正在保存'); ?>');
const data = new FormData(form.get(0));
data.append('do', 'save');
form.triggerHandler('submit');
$.ajax({
url: form.attr('action'),
processData: false,
contentType: false,
type: 'POST',
data: data,
success: callback,
error: function () {
autoSave.text('<?php _e('保存失败, 请重试'); ?>');
},
complete: function () {
form.trigger('submitted');
}
});
};
<?php if ($options->autoSave): ?>
// 自动保存
let saveTimer = null;
let stopAutoSave = false;
form.on('datachange', function () {
changed = true;
autoSave.text('<?php _e('尚未保存'); ?>' + (lastSaveTime ? ' (<?php _e('上次保存时间'); ?>: ' + lastSaveTime + ')' : ''));
if (saveTimer) {
clearTimeout(saveTimer);
}
saveTimer = setTimeout(function () {
!stopAutoSave && Typecho.savePost();
}, 3000);
}).on('submit', function () {
stopAutoSave = true;
}).on('submitted', function () {
stopAutoSave = false;
});
<?php else: ?>
form.on('datachange', function () {
changed = true;
});
<?php endif; ?>
// 计算夏令时偏移
const dstOffset = (function () {
const d = new Date(),
jan = new Date(d.getFullYear(), 0, 1),
jul = new Date(d.getFullYear(), 6, 1),
stdOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
return stdOffset - d.getTimezoneOffset();
})();
if (dstOffset > 0) {
$('<input name="dst" type="hidden" />').appendTo(form).val(dstOffset);
}
// 时区
$('<input name="timezone" type="hidden" />').appendTo(form).val(- (new Date).getTimezoneOffset() * 60);
// 预览功能
let isFullScreen = false;
function previewData(cid) {
isFullScreen = $(document.body).hasClass('fullscreen');
$(document.body).addClass('fullscreen preview');
const frame = $('<iframe frameborder="0" class="preview-frame preview-loading"></iframe>')
.attr('src', './preview.php?cid=' + cid)
.attr('sandbox', 'allow-same-origin allow-scripts')
.appendTo(document.body);
frame.load(function () {
frame.removeClass('preview-loading');
});
frame.height($(window).height() - 53);
}
function cancelPreview() {
if (!isFullScreen) {
$(document.body).removeClass('fullscreen');
}
$(document.body).removeClass('preview');
$('.preview-frame').remove();
}
$('#btn-cancel-preview').click(cancelPreview);
$(window).bind('message', function (e) {
if (e.originalEvent.data === 'cancelPreview') {
cancelPreview();
}
});
btnPreview.click(function () {
if (changed) {
if (confirm('<?php _e('修改后的内容需要保存后才能预览, 是否保存?'); ?>')) {
Typecho.savePost(function () {
previewData(draftId);
});
}
} else if (!!draftId) {
previewData(draftId);
} else if (!!cid) {
previewData(cid);
}
});
// 控制选项和附件的切换
$('#edit-secondary .typecho-option-tabs li').click(function() {
$('#edit-secondary .typecho-option-tabs li.active').removeClass('active');
$('#edit-secondary .tab-content').addClass('hidden');
const activeTab = $(this).addClass('active').find('a').attr('href');
$(activeTab).removeClass('hidden');
return false;
});
// 自动隐藏密码框
$('#visibility').change(function () {
const val = $(this).val(), password = $('#post-password');
if ('password' === val) {
password.removeClass('hidden');
} else {
password.addClass('hidden');
}
});
// 草稿删除确认
$('.edit-draft-notice a').click(function () {
if (confirm('<?php _e('您确认要删除这份草稿吗?'); ?>')) {
window.location.href = $(this).attr('href');
}
return false;
});
});
</script>

216
admin/write-page.php Executable file
View File

@@ -0,0 +1,216 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$page = \Widget\Contents\Page\Edit::alloc()->prepare();
$parentPageId = $page->getParent();
$parentPages = [0 => _t('不选择')];
$parents = \Widget\Contents\Page\Admin::allocWithAlias(
'options',
'ignoreRequest=1' . ($request->is('cid') ? '&ignore=' . $request->get('cid') : '')
);
while ($parents->next()) {
$parentPages[$parents->cid] = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $parents->levels) . $parents->title;
}
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<form class="row typecho-page-main typecho-post-area" action="<?php $security->index('/action/contents-page-edit'); ?>" method="post" name="write_page">
<div class="col-mb-12 col-tb-9" role="main">
<?php if ($page->draft): ?>
<?php if ($page->draft['cid'] != $page->cid): ?>
<?php $pageModifyDate = new \Typecho\Date($page->draft['modified']); ?>
<cite
class="edit-draft-notice"><?php _e('你正在编辑的是保存于 %s 的修订版, 你也可以 <a href="%s">删除它</a>', $pageModifyDate->word(),
$security->getIndex('/action/contents-page-edit?do=deleteDraft&cid=' . $page->cid)); ?></cite>
<?php else: ?>
<cite class="edit-draft-notice"><?php _e('当前正在编辑的是未发布的草稿'); ?></cite>
<?php endif; ?>
<input name="draft" type="hidden" value="<?php echo $page->draft['cid'] ?>"/>
<?php endif; ?>
<p class="title">
<label for="title" class="sr-only"><?php _e('标题'); ?></label>
<input type="text" id="title" name="title" autocomplete="off" value="<?php $page->title(); ?>"
placeholder="<?php _e('标题'); ?>" class="w-100 text title"/>
</p>
<?php $permalink = \Typecho\Common::url($options->routingTable['page']['url'], $options->index);
[$scheme, $permalink] = explode(':', $permalink, 2);
$permalink = ltrim($permalink, '/');
$permalink = preg_replace("/\[([_a-z0-9-]+)[^\]]*\]/i", "{\\1}", $permalink);
if ($page->have()) {
$permalink = preg_replace_callback(
"/\{(cid)\}/i",
function ($matches) use ($page) {
$key = $matches[1];
return $page->getRouterParam($key);
},
$permalink
);
}
$input = '<input type="text" id="slug" name="slug" autocomplete="off" value="' . htmlspecialchars($page->slug ?? '') . '" class="mono" />';
?>
<p class="mono url-slug">
<label for="slug" class="sr-only"><?php _e('网址缩略名'); ?></label>
<?php echo preg_replace_callback("/\{(slug|directory)\}/i", function ($matches) use ($input) {
if ($matches[1] == 'slug') {
return $input;
} else {
return '{directory/' . $input . '}';
}
}, $permalink); ?>
</p>
<p>
<label for="text" class="sr-only"><?php _e('页面内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($page->text); ?></textarea>
</p>
<?php include 'custom-fields.php'; ?>
<p class="submit">
<span class="left">
<button type="button" id="btn-cancel-preview" class="btn"><i
class="i-caret-left"></i> <?php _e('取消预览'); ?></button>
</span>
<span class="right">
<input type="hidden" name="do" value="publish" />
<input type="hidden" name="cid" value="<?php $page->cid(); ?>"/>
<button type="button" id="btn-preview" class="btn"><i
class="i-exlink"></i> <?php _e('预览页面'); ?></button>
<button type="submit" name="do" value="save" id="btn-save"
class="btn"><?php _e('保存草稿'); ?></button>
<button type="submit" name="do" value="publish" class="btn primary"
id="btn-submit"><?php _e('发布页面'); ?></button>
<?php if ($options->markdown && (!$page->have() || $page->isMarkdown)): ?>
<input type="hidden" name="markdown" value="1"/>
<?php endif; ?>
</span>
</p>
<?php \Typecho\Plugin::factory('admin/write-page.php')->call('content', $page); ?>
</div>
<div id="edit-secondary" class="col-mb-12 col-tb-3" role="complementary">
<ul class="typecho-option-tabs">
<li class="active w-50"><a href="#tab-advance"><?php _e('选项'); ?></a></li>
<li class="w-50"><a href="#tab-files" id="tab-files-btn"><?php _e('附件'); ?></a></li>
</ul>
<div id="tab-advance" class="tab-content">
<section class="typecho-post-option" role="application">
<label for="date" class="typecho-label"><?php _e('发布日期'); ?></label>
<p><input class="typecho-date w-100" type="text" name="date" id="date" autocomplete="off"
value="<?php $page->have() && $page->created > 0 ? $page->date('Y-m-d H:i') : ''; ?>"/>
</p>
</section>
<section class="typecho-post-option">
<label for="order" class="typecho-label"><?php _e('页面顺序'); ?></label>
<p><input type="number" id="order" name="order" value="<?php $page->order(); ?>"
class="w-100"/></p>
<p class="description"><?php _e('为你的自定义页面设定一个序列值以后, 能够使得它们按此值从小到大排列'); ?></p>
</section>
<section class="typecho-post-option">
<label for="template" class="typecho-label"><?php _e('自定义模板'); ?></label>
<p>
<select name="template" id="template">
<option value=""><?php _e('不选择'); ?></option>
<?php $templates = $page->getTemplates();
foreach ($templates as $template => $name): ?>
<option
value="<?php echo $template; ?>"<?php if ($template == $page->template): ?> selected="true"<?php endif; ?>><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
</p>
<p class="description"><?php _e('如果你为此页面选择了一个自定义模板, 系统将按照你选择的模板文件展现它'); ?></p>
</section>
<section class="typecho-post-option">
<label for="parent" class="typecho-label"><?php _e('父级页面'); ?></label>
<p>
<select name="parent" id="parent">
<?php foreach ($parentPages as $pageId => $pageTitle): ?>
<option
value="<?php echo $pageId; ?>"<?php if ($pageId == ($page->parent ?? $parentPageId)): ?> selected="true"<?php endif; ?>><?php echo $pageTitle; ?></option>
<?php endforeach; ?>
</select>
</p>
<p class="description"><?php _e('如果你设定了父级页面, 此页面将作为子页面呈现'); ?></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-page.php')->call('option', $page); ?>
<details id="advance-panel">
<summary class="btn btn-xs"><?php _e('高级选项'); ?> <i class="i-caret-down"></i></summary>
<section class="typecho-post-option visibility-option">
<label for="visibility" class="typecho-label"><?php _e('公开度'); ?></label>
<p>
<select id="visibility" name="visibility">
<option
value="publish"<?php if ($page->status == 'publish' || !$page->status): ?> selected<?php endif; ?>><?php _e('公开'); ?></option>
<option
value="hidden"<?php if ($page->status == 'hidden'): ?> selected<?php endif; ?>><?php _e('隐藏'); ?></option>
</select>
</p>
</section>
<section class="typecho-post-option allow-option">
<label class="typecho-label"><?php _e('权限控制'); ?></label>
<ul>
<li><input id="allowComment" name="allowComment" type="checkbox" value="1"
<?php if ($page->allow('comment')): ?>checked="true"<?php endif; ?> />
<label for="allowComment"><?php _e('允许评论'); ?></label></li>
<li><input id="allowPing" name="allowPing" type="checkbox" value="1"
<?php if ($page->allow('ping')): ?>checked="true"<?php endif; ?> />
<label for="allowPing"><?php _e('允许被引用'); ?></label></li>
<li><input id="allowFeed" name="allowFeed" type="checkbox" value="1"
<?php if ($page->allow('feed')): ?>checked="true"<?php endif; ?> />
<label for="allowFeed"><?php _e('允许在聚合中出现'); ?></label></li>
</ul>
</section>
<?php \Typecho\Plugin::factory('admin/write-page.php')->call('advanceOption', $page); ?>
</details>
<?php if ($page->have()): ?>
<?php $modified = new \Typecho\Date($page->modified); ?>
<section class="typecho-post-option">
<p class="description">
<br>&mdash;<br>
<?php _e('本页面由 <a href="%s">%s</a> 创建',
\Typecho\Common::url('manage-pages.php?uid=' . $page->author->uid, $options->adminUrl), $page->author->screenName); ?>
<br>
<?php _e('最后更新于 %s', $modified->word()); ?>
</p>
</section>
<?php endif; ?>
</div><!-- end #tab-advance -->
<div id="tab-files" class="tab-content hidden">
<?php include 'file-upload.php'; ?>
</div><!-- end #tab-files -->
</div>
</form>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'write-js.php';
\Typecho\Plugin::factory('admin/write-page.php')->trigger($plugged)->call('richEditor', $page);
if (!$plugged) {
include 'editor-js.php';
}
include 'file-upload-js.php';
include 'custom-fields-js.php';
\Typecho\Plugin::factory('admin/write-page.php')->bottom($page);
include 'footer.php';
?>

213
admin/write-post.php Executable file
View File

@@ -0,0 +1,213 @@
<?php
include 'common.php';
include 'header.php';
include 'menu.php';
$post = \Widget\Contents\Post\Edit::alloc()->prepare();
?>
<main class="main">
<div class="body container">
<?php include 'page-title.php'; ?>
<form class="row typecho-page-main typecho-post-area" action="<?php $security->index('/action/contents-post-edit'); ?>" method="post" name="write_post">
<div class="col-mb-12 col-tb-9" role="main">
<?php if ($post->draft): ?>
<?php if ($post->draft['cid'] != $post->cid): ?>
<?php $postModifyDate = new \Typecho\Date($post->draft['modified']); ?>
<cite
class="edit-draft-notice"><?php _e('你正在编辑的是保存于 %s 的修订版, 你也可以 <a href="%s">删除它</a>', $postModifyDate->word(),
$security->getIndex('/action/contents-post-edit?do=deleteDraft&cid=' . $post->cid)); ?></cite>
<?php else: ?>
<cite class="edit-draft-notice"><?php _e('当前正在编辑的是未发布的草稿'); ?></cite>
<?php endif; ?>
<input name="draft" type="hidden" value="<?php echo $post->draft['cid'] ?>"/>
<?php endif; ?>
<p class="title">
<label for="title" class="sr-only"><?php _e('标题'); ?></label>
<input type="text" id="title" name="title" autocomplete="off" value="<?php $post->title(); ?>"
placeholder="<?php _e('标题'); ?>" class="w-100 text title"/>
</p>
<?php $permalink = \Typecho\Common::url($options->routingTable['post']['url'], $options->index);
[$scheme, $permalink] = explode(':', $permalink, 2);
$permalink = ltrim($permalink, '/');
$permalink = preg_replace("/\[([_a-z0-9-]+)[^\]]*\]/i", "{\\1}", $permalink);
if ($post->have()) {
$permalink = preg_replace_callback(
"/\{(cid|category|year|month|day)\}/i",
function ($matches) use ($post) {
$key = $matches[1];
return $post->getRouterParam($key);
},
$permalink
);
}
$input = '<input type="text" id="slug" name="slug" autocomplete="off" value="' . htmlspecialchars($post->slug ?? '') . '" class="mono" />';
?>
<p class="mono url-slug">
<label for="slug" class="sr-only"><?php _e('网址缩略名'); ?></label>
<?php echo preg_replace("/\{slug\}/i", $input, $permalink); ?>
</p>
<p>
<label for="text" class="sr-only"><?php _e('文章内容'); ?></label>
<textarea style="height: <?php $options->editorSize(); ?>px" autocomplete="off" id="text"
name="text" class="w-100 mono"><?php echo htmlspecialchars($post->text); ?></textarea>
</p>
<?php include 'custom-fields.php'; ?>
<p class="submit">
<span class="left">
<button type="button" id="btn-cancel-preview" class="btn"><i
class="i-caret-left"></i> <?php _e('取消预览'); ?></button>
</span>
<span class="right">
<input type="hidden" name="do" value="publish" />
<input type="hidden" name="cid" value="<?php $post->cid(); ?>"/>
<button type="button" id="btn-preview" class="btn"><i
class="i-exlink"></i> <?php _e('预览文章'); ?></button>
<button type="submit" name="do" value="save" id="btn-save"
class="btn"><?php _e('保存草稿'); ?></button>
<button type="submit" name="do" value="publish" class="btn primary"
id="btn-submit"><?php _e('发布文章'); ?></button>
<?php if ($options->markdown && (!$post->have() || $post->isMarkdown)): ?>
<input type="hidden" name="markdown" value="1"/>
<?php endif; ?>
</span>
</p>
<?php \Typecho\Plugin::factory('admin/write-post.php')->call('content', $post); ?>
</div>
<div id="edit-secondary" class="col-mb-12 col-tb-3" role="complementary">
<ul class="typecho-option-tabs">
<li class="active w-50"><a href="#tab-advance"><?php _e('选项'); ?></a></li>
<li class="w-50"><a href="#tab-files" id="tab-files-btn"><?php _e('附件'); ?></a></li>
</ul>
<div id="tab-advance" class="tab-content">
<section class="typecho-post-option" role="application">
<label for="date" class="typecho-label"><?php _e('发布日期'); ?></label>
<p><input class="typecho-date w-100" type="text" name="date" id="date" autocomplete="off"
value="<?php $post->have() && $post->created > 0 ? $post->date('Y-m-d H:i') : ''; ?>"/>
</p>
</section>
<section class="typecho-post-option category-option">
<label class="typecho-label"><?php _e('分类'); ?></label>
<?php \Widget\Metas\Category\Rows::alloc()->to($category); ?>
<ul>
<?php $categories = array_column($post->categories, 'mid'); ?>
<?php while ($category->next()): ?>
<li><?php echo str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;', $category->levels); ?><input
type="checkbox" id="category-<?php $category->mid(); ?>"
value="<?php $category->mid(); ?>" name="category[]"
<?php if (in_array($category->mid, $categories)): ?>checked="true"<?php endif; ?>/>
<label
for="category-<?php $category->mid(); ?>"><?php $category->name(); ?></label>
</li>
<?php endwhile; ?>
</ul>
</section>
<section class="typecho-post-option">
<label for="token-input-tags" class="typecho-label"><?php _e('标签'); ?></label>
<p><input id="tags" name="tags" type="text" value="<?php $post->have() ? $post->tags(',', false) : ''; ?>"
class="w-100 text"/></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-post.php')->call('option', $post); ?>
<details id="advance-panel">
<summary class="btn btn-xs"><?php _e('高级选项'); ?> <i class="i-caret-down"></i></summary>
<?php if ($user->pass('editor', true)): ?>
<section class="typecho-post-option visibility-option">
<label for="visibility" class="typecho-label"><?php _e('公开度'); ?></label>
<p>
<select id="visibility" name="visibility">
<?php if ($user->pass('editor', true)): ?>
<option
value="publish"<?php if (($post->status == 'publish' && !$post->password) || !$post->status): ?> selected<?php endif; ?>><?php _e('公开'); ?></option>
<option
value="hidden"<?php if ($post->status == 'hidden'): ?> selected<?php endif; ?>><?php _e('隐藏'); ?></option>
<option
value="password"<?php if (strlen($post->password ?? '') > 0): ?> selected<?php endif; ?>><?php _e('密码保护'); ?></option>
<option
value="private"<?php if ($post->status == 'private'): ?> selected<?php endif; ?>><?php _e('私密'); ?></option>
<?php endif; ?>
<option
value="waiting"<?php if (!$user->pass('editor', true) || $post->status == 'waiting'): ?> selected<?php endif; ?>><?php _e('待审核'); ?></option>
</select>
</p>
<p id="post-password"<?php if (strlen($post->password ?? '') == 0): ?> class="hidden"<?php endif; ?>>
<label for="protect-pwd" class="sr-only">内容密码</label>
<input type="text" name="password" id="protect-pwd" class="text-s"
value="<?php $post->password(); ?>" size="16"
placeholder="<?php _e('内容密码'); ?>" autocomplete="off"/>
</p>
</section>
<?php endif; ?>
<section class="typecho-post-option allow-option">
<label class="typecho-label"><?php _e('权限控制'); ?></label>
<ul>
<li><input id="allowComment" name="allowComment" type="checkbox" value="1"
<?php if ($post->allow('comment')): ?>checked="true"<?php endif; ?> />
<label for="allowComment"><?php _e('允许评论'); ?></label></li>
<li><input id="allowPing" name="allowPing" type="checkbox" value="1"
<?php if ($post->allow('ping')): ?>checked="true"<?php endif; ?> />
<label for="allowPing"><?php _e('允许被引用'); ?></label></li>
<li><input id="allowFeed" name="allowFeed" type="checkbox" value="1"
<?php if ($post->allow('feed')): ?>checked="true"<?php endif; ?> />
<label for="allowFeed"><?php _e('允许在聚合中出现'); ?></label></li>
</ul>
</section>
<section class="typecho-post-option">
<label for="trackback" class="typecho-label"><?php _e('引用通告'); ?></label>
<p><textarea id="trackback" class="w-100 mono" name="trackback" rows="2"></textarea></p>
<p class="description"><?php _e('每一行一个引用地址, 用回车隔开'); ?></p>
</section>
<?php \Typecho\Plugin::factory('admin/write-post.php')->call('advanceOption', $post); ?>
</details><!-- end #advance-panel -->
<?php if ($post->have()): ?>
<?php $modified = new \Typecho\Date($post->modified); ?>
<section class="typecho-post-option">
<p class="description">
<br>&mdash;<br>
<?php _e('本文由 <a href="%s">%s</a> 撰写',
\Typecho\Common::url('manage-posts.php?uid=' . $post->author->uid, $options->adminUrl), $post->author->screenName); ?>
<br>
<?php _e('最后更新于 %s', $modified->word()); ?>
</p>
</section>
<?php endif; ?>
</div><!-- end #tab-advance -->
<div id="tab-files" class="tab-content hidden">
<?php include 'file-upload.php'; ?>
</div><!-- end #tab-files -->
</div>
</form>
</div>
</main>
<?php
include 'copyright.php';
include 'common-js.php';
include 'form-js.php';
include 'write-js.php';
\Typecho\Plugin::factory('admin/write-post.php')->trigger($plugged)->call('richEditor', $post);
if (!$plugged) {
include 'editor-js.php';
}
include 'file-upload-js.php';
include 'custom-fields-js.php';
\Typecho\Plugin::factory('admin/write-post.php')->call('bottom', $post);
include 'footer.php';
?>

34
config.inc.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
// site root path
define('__TYPECHO_ROOT_DIR__', dirname(__FILE__));
// plugin directory (relative path)
define('__TYPECHO_PLUGIN_DIR__', '/usr/plugins');
// theme directory (relative path)
define('__TYPECHO_THEME_DIR__', '/usr/themes');
// admin directory (relative path)
define('__TYPECHO_ADMIN_DIR__', '/admin/');
// register autoload
require_once __TYPECHO_ROOT_DIR__ . '/var/Typecho/Common.php';
//define('__TYPECHO_DEBUG__', true);
// init
\Typecho\Common::init();
// config db
$db = new \Typecho\Db('Pdo_Mysql', 'typecho_');
$db->addServer(array (
'host' => 'localhost',
'port' => 3306,
'user' => 'www_beihong_wang',
'password' => 'K71bT81AbbFJXad9',
'charset' => 'utf8mb4',
'database' => 'www_beihong_wang',
'engine' => 'InnoDB',
'sslCa' => NULL,
'sslVerify' => false,
), \Typecho\Db::READ | \Typecho\Db::WRITE);
\Typecho\Db::set($db);

BIN
img/ALI_PAY.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
img/ICP图标.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
img/WECHAT_PAY.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
img/favicon.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

BIN
img/备案图标.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

39
index.html Normal file
View File

@@ -0,0 +1,39 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>恭喜,站点创建成功!</title>
<style>
.container {
width: 60%;
margin: 10% auto 0;
background-color: #f0f0f0;
padding: 2% 5%;
border-radius: 10px
}
ul {
padding-left: 20px;
}
ul li {
line-height: 2.3
}
a {
color: #20a53a
}
</style>
</head>
<body>
<div class="container">
<h1>恭喜, 站点创建成功!</h1>
<h3>这是默认index.html本页面由系统自动生成</h3>
<ul>
<li>本页面在FTP根目录下的index.html</li>
<li>您可以修改、删除或覆盖本页面</li>
<li>FTP相关信息请到“面板系统后台 > FTP” 查看</li>
</ul>
</div>
</body>
</html>

26
index.php Executable file
View File

@@ -0,0 +1,26 @@
<?php
/**
* Typecho Blog Platform
*
* @copyright Copyright (c) 2008 Typecho team (http://www.typecho.org)
* @license GNU General Public License 2.0
* @version $Id: index.php 1153 2009-07-02 10:53:22Z magike.net $
*/
/** 载入配置支持 */
if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once 'config.inc.php') {
file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
exit;
}
/** 初始化组件 */
\Widget\Init::alloc();
/** 注册一个初始化插件 */
\Typecho\Plugin::factory('index.php')->call('begin');
/** 开始路由分发 */
\Typecho\Router::dispatch();
/** 注册一个结束插件 */
\Typecho\Plugin::factory('index.php')->call('end');

1504
install.php Executable file

File diff suppressed because it is too large Load Diff

84
install/Mysql.php Executable file
View File

@@ -0,0 +1,84 @@
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
<input type="text" class="text" name="dbUser" id="dbUser" value="" />
<p class="description"><?php _e('您可能会使用 "%s"', 'root'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
</li>
</ul>
<details>
<summary>
<strong><?php _e('高级选项'); ?></strong>
</summary>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
<input type="text" class="text" name="dbPort" id="dbPort" value="3306"/>
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbCharset"><?php _e('数据库编码'); ?></label>
<select name="dbCharset" id="dbCharset">
<option value="utf8mb4">utf8mb4</option>
<option value="utf8">utf8</option>
</select>
<p class="description"><?php _e('选择 utf8mb4 编码至少需要 MySQL 5.5.3 版本'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbEngine"><?php _e('数据库引擎'); ?></label>
<select name="dbEngine" id="dbEngine">
<option value="InnoDB">InnoDB</option>
<option value="MyISAM">MyISAM</option>
</select>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbSslCa"><?php _e('数据库 SSL 证书'); ?></label>
<input type="text" class="text" name="dbSslCa" id="dbSslCa"/>
<p class="description"><?php _e('如果您的数据库启用了 SSL请填写 CA 证书路径,否则请留空'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbSslVerify"><?php _e('启用数据库 SSL 服务端证书验证'); ?></label>
<select name="dbSslVerify" id="dbSslVerify">
<option value="off"><?php _e('不启用'); ?></option>
<option value="on"><?php _e('启用'); ?></option>
</select>
</li>
</ul>
</details>

152
install/Mysql.sql Executable file
View File

@@ -0,0 +1,152 @@
-- phpMyAdmin SQL Dump
-- version 2.11.5
-- http://www.phpmyadmin.net
--
-- 主机: localhost
-- 生成日期: 2008 年 07 月 06 日 18:00
-- 服务器版本: 5.0.51
-- PHP 版本: 5.2.5
--
-- 数据库: `typecho`
--
-- --------------------------------------------------------
--
-- 表的结构 `typecho_comments`
--
CREATE TABLE `typecho_comments` (
`coid` int(10) unsigned NOT NULL auto_increment,
`cid` int(10) unsigned default '0',
`created` int(10) unsigned default '0',
`author` varchar(150) default NULL,
`authorId` int(10) unsigned default '0',
`ownerId` int(10) unsigned default '0',
`mail` varchar(150) default NULL,
`url` varchar(255) default NULL,
`ip` varchar(64) default NULL,
`agent` varchar(511) default NULL,
`text` text,
`type` varchar(16) default 'comment',
`status` varchar(16) default 'approved',
`parent` int(10) unsigned default '0',
PRIMARY KEY (`coid`),
KEY `cid` (`cid`),
KEY `created` (`created`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;
-- --------------------------------------------------------
--
-- 表的结构 `typecho_contents`
--
CREATE TABLE `typecho_contents` (
`cid` int(10) unsigned NOT NULL auto_increment,
`title` varchar(150) default NULL,
`slug` varchar(150) default NULL,
`created` int(10) unsigned default '0',
`modified` int(10) unsigned default '0',
`text` longtext,
`order` int(10) unsigned default '0',
`authorId` int(10) unsigned default '0',
`template` varchar(32) default NULL,
`type` varchar(16) default 'post',
`status` varchar(16) default 'publish',
`password` varchar(32) default NULL,
`commentsNum` int(10) unsigned default '0',
`allowComment` char(1) default '0',
`allowPing` char(1) default '0',
`allowFeed` char(1) default '0',
`parent` int(10) unsigned default '0',
PRIMARY KEY (`cid`),
UNIQUE KEY `slug` (`slug`),
KEY `created` (`created`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;
-- --------------------------------------------------------
--
-- 表的结构 `typecho_fields`
--
CREATE TABLE `typecho_fields` (
`cid` int(10) unsigned NOT NULL,
`name` varchar(150) NOT NULL,
`type` varchar(8) default 'str',
`str_value` text,
`int_value` int(10) default '0',
`float_value` float default '0',
PRIMARY KEY (`cid`,`name`),
KEY `int_value` (`int_value`),
KEY `float_value` (`float_value`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;
-- --------------------------------------------------------
--
-- 表的结构 `typecho_metas`
--
CREATE TABLE `typecho_metas` (
`mid` int(10) unsigned NOT NULL auto_increment,
`name` varchar(150) default NULL,
`slug` varchar(150) default NULL,
`type` varchar(32) NOT NULL,
`description` varchar(150) default NULL,
`count` int(10) unsigned default '0',
`order` int(10) unsigned default '0',
`parent` int(10) unsigned default '0',
PRIMARY KEY (`mid`),
KEY `slug` (`slug`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;
-- --------------------------------------------------------
--
-- 表的结构 `typecho_options`
--
CREATE TABLE `typecho_options` (
`name` varchar(32) NOT NULL,
`user` int(10) unsigned NOT NULL default '0',
`value` text,
PRIMARY KEY (`name`,`user`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;
-- --------------------------------------------------------
--
-- 表的结构 `typecho_relationships`
--
CREATE TABLE `typecho_relationships` (
`cid` int(10) unsigned NOT NULL,
`mid` int(10) unsigned NOT NULL,
PRIMARY KEY (`cid`,`mid`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;
-- --------------------------------------------------------
--
-- 表的结构 `typecho_users`
--
CREATE TABLE `typecho_users` (
`uid` int(10) unsigned NOT NULL auto_increment,
`name` varchar(32) default NULL,
`password` varchar(64) default NULL,
`mail` varchar(150) default NULL,
`url` varchar(150) default NULL,
`screenName` varchar(32) default NULL,
`created` int(10) unsigned default '0',
`activated` int(10) unsigned default '0',
`logged` int(10) unsigned default '0',
`group` varchar(16) default 'visitor',
`authCode` varchar(64) default NULL,
PRIMARY KEY (`uid`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `mail` (`mail`)
) ENGINE=%engine% DEFAULT CHARSET=%charset%;

54
install/Pgsql.php Executable file
View File

@@ -0,0 +1,54 @@
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbHost"><?php _e('数据库地址'); ?></label>
<input type="text" class="text" name="dbHost" id="dbHost" value="localhost"/>
<p class="description"><?php _e('您可能会使用 "%s"', 'localhost'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbUser"><?php _e('数据库用户名'); ?></label>
<input type="text" class="text" name="dbUser" id="dbUser" value="postgres" />
<p class="description"><?php _e('您可能会使用 "%s"', 'postgres'); ?></p>
</li>
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbPassword"><?php _e('数据库密码'); ?></label>
<input type="password" class="text" name="dbPassword" id="dbPassword" value="" />
</li
</ul>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbDatabase"><?php _e('数据库名'); ?></label>
<input type="text" class="text" name="dbDatabase" id="dbDatabase" value="" />
<p class="description"><?php _e('请您指定数据库名称'); ?></p>
</li
</ul>
<details>
<summary>
<strong><?php _e('高级选项'); ?></strong>
</summary>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbPort"><?php _e('数据库端口'); ?></label>
<input type="text" class="text" name="dbPort" id="dbPort" value="5432"/>
<p class="description"><?php _e('如果您不知道此选项的意义, 请保留默认设置'); ?></p>
</li>
</ul>
<input type="hidden" name="dbCharset" value="utf8" />
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbSslVerify"><?php _e('启用数据库 SSL 服务端证书验证'); ?></label>
<select name="dbSslVerify" id="dbSslVerify">
<option value="off"><?php _e('不启用'); ?></option>
<option value="on"><?php _e('启用'); ?></option>
</select>
</li>
</ul>
</details>

130
install/Pgsql.sql Executable file
View File

@@ -0,0 +1,130 @@
--
-- Table structure for table "typecho_comments"
--
CREATE SEQUENCE "typecho_comments_seq";
CREATE TABLE "typecho_comments" ( "coid" INT NOT NULL DEFAULT nextval('typecho_comments_seq'),
"cid" INT NULL DEFAULT '0',
"created" INT NULL DEFAULT '0',
"author" VARCHAR(150) NULL DEFAULT NULL,
"authorId" INT NULL DEFAULT '0',
"ownerId" INT NULL DEFAULT '0',
"mail" VARCHAR(150) NULL DEFAULT NULL,
"url" VARCHAR(255) NULL DEFAULT NULL,
"ip" VARCHAR(64) NULL DEFAULT NULL,
"agent" VARCHAR(511) NULL DEFAULT NULL,
"text" TEXT NULL DEFAULT NULL,
"type" VARCHAR(16) NULL DEFAULT 'comment',
"status" VARCHAR(16) NULL DEFAULT 'approved',
"parent" INT NULL DEFAULT '0',
PRIMARY KEY ("coid")
);
CREATE INDEX "typecho_comments_cid" ON "typecho_comments" ("cid");
CREATE INDEX "typecho_comments_created" ON "typecho_comments" ("created");
--
-- Table structure for table "typecho_contents"
--
CREATE SEQUENCE "typecho_contents_seq";
CREATE TABLE "typecho_contents" ( "cid" INT NOT NULL DEFAULT nextval('typecho_contents_seq'),
"title" VARCHAR(150) NULL DEFAULT NULL,
"slug" VARCHAR(150) NULL DEFAULT NULL,
"created" INT NULL DEFAULT '0',
"modified" INT NULL DEFAULT '0',
"text" TEXT NULL DEFAULT NULL,
"order" INT NULL DEFAULT '0',
"authorId" INT NULL DEFAULT '0',
"template" VARCHAR(32) NULL DEFAULT NULL,
"type" VARCHAR(16) NULL DEFAULT 'post',
"status" VARCHAR(16) NULL DEFAULT 'publish',
"password" VARCHAR(32) NULL DEFAULT NULL,
"commentsNum" INT NULL DEFAULT '0',
"allowComment" CHAR(1) NULL DEFAULT '0',
"allowPing" CHAR(1) NULL DEFAULT '0',
"allowFeed" CHAR(1) NULL DEFAULT '0',
"parent" INT NULL DEFAULT '0',
PRIMARY KEY ("cid"),
UNIQUE ("slug")
);
CREATE INDEX "typecho_contents_created" ON "typecho_contents" ("created");
--
-- Table structure for table "typecho_fields"
--
CREATE TABLE "typecho_fields" ("cid" INT NOT NULL,
"name" VARCHAR(150) NOT NULL,
"type" VARCHAR(8) NULL DEFAULT 'str',
"str_value" TEXT NULL DEFAULT NULL,
"int_value" INT NULL DEFAULT '0',
"float_value" REAL NULL DEFAULT '0',
PRIMARY KEY ("cid","name")
);
CREATE INDEX "typecho_fields_int_value" ON "typecho_fields" ("int_value");
CREATE INDEX "typecho_fields_float_value" ON "typecho_fields" ("float_value");
--
-- Table structure for table "typecho_metas"
--
CREATE SEQUENCE "typecho_metas_seq";
CREATE TABLE "typecho_metas" ( "mid" INT NOT NULL DEFAULT nextval('typecho_metas_seq'),
"name" VARCHAR(150) NULL DEFAULT NULL,
"slug" VARCHAR(150) NULL DEFAULT NULL,
"type" VARCHAR(16) NOT NULL DEFAULT '',
"description" VARCHAR(150) NULL DEFAULT NULL,
"count" INT NULL DEFAULT '0',
"order" INT NULL DEFAULT '0',
"parent" INT NULL DEFAULT '0',
PRIMARY KEY ("mid")
);
CREATE INDEX "typecho_metas_slug" ON "typecho_metas" ("slug");
--
-- Table structure for table "typecho_options"
--
CREATE TABLE "typecho_options" ( "name" VARCHAR(32) NOT NULL DEFAULT '',
"user" INT NOT NULL DEFAULT '0',
"value" TEXT NULL DEFAULT NULL,
PRIMARY KEY ("name","user")
);
--
-- Table structure for table "typecho_relationships"
--
CREATE TABLE "typecho_relationships" ( "cid" INT NOT NULL DEFAULT '0',
"mid" INT NOT NULL DEFAULT '0',
PRIMARY KEY ("cid","mid")
);
--
-- Table structure for table "typecho_users"
--
CREATE SEQUENCE "typecho_users_seq";
CREATE TABLE "typecho_users" ( "uid" INT NOT NULL DEFAULT nextval('typecho_users_seq') ,
"name" VARCHAR(32) NULL DEFAULT NULL,
"password" VARCHAR(64) NULL DEFAULT NULL,
"mail" VARCHAR(150) NULL DEFAULT NULL,
"url" VARCHAR(150) NULL DEFAULT NULL,
"screenName" VARCHAR(32) NULL DEFAULT NULL,
"created" INT NULL DEFAULT '0',
"activated" INT NULL DEFAULT '0',
"logged" INT NULL DEFAULT '0',
"group" VARCHAR(16) NULL DEFAULT 'visitor',
"authCode" VARCHAR(64) NULL DEFAULT NULL,
PRIMARY KEY ("uid"),
UNIQUE ("name"),
UNIQUE ("mail")
);

9
install/SQLite.php Executable file
View File

@@ -0,0 +1,9 @@
<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php $defaultDir = __TYPECHO_ROOT_DIR__ . '/usr/' . uniqid() . '.db'; ?>
<ul class="typecho-option">
<li>
<label class="typecho-label" for="dbFile"><?php _e('数据库文件路径'); ?></label>
<input type="text" class="text" name="dbFile" id="dbFile" value="<?php echo $defaultDir; ?>"/>
<p class="description"><?php _e('"%s" 是我们为您自动生成的地址', $defaultDir); ?></p>
</li>
</ul>

87
install/SQLite.sql Executable file
View File

@@ -0,0 +1,87 @@
CREATE TABLE typecho_comments ( "coid" INTEGER NOT NULL PRIMARY KEY,
"cid" int(10) default '0' ,
"created" int(10) default '0' ,
"author" varchar(150) default NULL ,
"authorId" int(10) default '0' ,
"ownerId" int(10) default '0' ,
"mail" varchar(150) default NULL ,
"url" varchar(255) default NULL ,
"ip" varchar(64) default NULL ,
"agent" varchar(511) default NULL ,
"text" text ,
"type" varchar(16) default 'comment' ,
"status" varchar(16) default 'approved' ,
"parent" int(10) default '0' );
CREATE INDEX typecho_comments_cid ON typecho_comments ("cid");
CREATE INDEX typecho_comments_created ON typecho_comments ("created");
CREATE TABLE typecho_contents ( "cid" INTEGER NOT NULL PRIMARY KEY,
"title" varchar(150) default NULL ,
"slug" varchar(150) default NULL ,
"created" int(10) default '0' ,
"modified" int(10) default '0' ,
"text" text ,
"order" int(10) default '0' ,
"authorId" int(10) default '0' ,
"template" varchar(32) default NULL ,
"type" varchar(16) default 'post' ,
"status" varchar(16) default 'publish' ,
"password" varchar(32) default NULL ,
"commentsNum" int(10) default '0' ,
"allowComment" char(1) default '0' ,
"allowPing" char(1) default '0' ,
"allowFeed" char(1) default '0' ,
"parent" int(10) default '0' );
CREATE UNIQUE INDEX typecho_contents_slug ON typecho_contents ("slug");
CREATE INDEX typecho_contents_created ON typecho_contents ("created");
CREATE TABLE "typecho_fields" ("cid" INTEGER NOT NULL,
"name" varchar(150) NOT NULL,
"type" varchar(8) default 'str',
"str_value" text,
"int_value" int(10) default '0',
"float_value" real default '0'
);
CREATE UNIQUE INDEX typecho_fields_cid_name ON typecho_fields ("cid", "name");
CREATE INDEX typecho_fields_int_value ON typecho_fields ("int_value");
CREATE INDEX typecho_fields_float_value ON typecho_fields ("float_value");
CREATE TABLE typecho_metas ( "mid" INTEGER NOT NULL PRIMARY KEY,
"name" varchar(150) default NULL ,
"slug" varchar(150) default NULL ,
"type" varchar(32) NOT NULL ,
"description" varchar(150) default NULL ,
"count" int(10) default '0' ,
"order" int(10) default '0' ,
"parent" int(10) default '0');
CREATE INDEX typecho_metas_slug ON typecho_metas ("slug");
CREATE TABLE typecho_options ( "name" varchar(32) NOT NULL ,
"user" int(10) NOT NULL default '0' ,
"value" text );
CREATE UNIQUE INDEX typecho_options_name_user ON typecho_options ("name", "user");
CREATE TABLE typecho_relationships ( "cid" int(10) NOT NULL ,
"mid" int(10) NOT NULL );
CREATE UNIQUE INDEX typecho_relationships_cid_mid ON typecho_relationships ("cid", "mid");
CREATE TABLE typecho_users ( "uid" INTEGER NOT NULL PRIMARY KEY,
"name" varchar(32) default NULL ,
"password" varchar(64) default NULL ,
"mail" varchar(150) default NULL ,
"url" varchar(150) default NULL ,
"screenName" varchar(32) default NULL ,
"created" int(10) default '0' ,
"activated" int(10) default '0' ,
"logged" int(10) default '0' ,
"group" varchar(16) default 'visitor' ,
"authCode" varchar(64) default NULL);
CREATE UNIQUE INDEX typecho_users_name ON typecho_users ("name");
CREATE UNIQUE INDEX typecho_users_mail ON typecho_users ("mail");

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) Taylor Otwell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,112 @@
<?php
namespace TypechoPlugin\MarkdownParse;
require_once 'phar://' . __DIR__ . '/vendor.phar/MarkdownParse.php';
use Typecho\Plugin\PluginInterface;
use Typecho\Widget\Helper\Form;
use Widget\Options;
/**
* 符合 CommonMark 和 GFMGitHub-Flavored Markdown规范的 Markdown 解析插件,强大而丰富的功能助你在不同平台上展现一致的出色
*
* @author mrgeneral
* @package MarkdownParse
* @version 2.6.0
* @link https://www.chengxiaobai.cn/
*/
class Plugin implements PluginInterface
{
const RADIO_VALUE_DISABLE = 0;
const RADIO_VALUE_AUTO = 1;
const RADIO_VALUE_FORCE = 2;
const CDN_SOURCE_DEFAULT = 'baomitu';
const CDN_SOURCE_MERMAID = [
'jsDelivr' => 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs',
'cdnjs' => 'https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs',
'baomitu' => 'https://lib.baomitu.com/mermaid/10.7.0/mermaid.esm.min.mjs'
];
const CDN_SOURCE_MATHJAX = [
'jsDelivr' => 'https://cdn.jsdelivr.net/npm/mathjax/es5/tex-mml-chtml.min.js',
'cdnjs' => 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js',
'baomitu' => 'https://lib.baomitu.com/mathjax/latest/es5/tex-mml-chtml.min.js'
];
public static function activate()
{
\Typecho\Plugin::factory('\Widget\Base\Contents')->markdown = [__CLASS__, 'parse'];
\Typecho\Plugin::factory('\Widget\Base\Comments')->markdown = [__CLASS__, 'parse'];
\Typecho\Plugin::factory('Widget_Archive')->footer = [__CLASS__, 'resourceLink'];
}
public static function deactivate()
{
// TODO: Implement deactivate() method.
}
public static function config(Form $form)
{
$elementToc = new Form\Element\Radio('is_available_toc', [self::RADIO_VALUE_DISABLE => _t('不解析'), self::RADIO_VALUE_AUTO => _t('解析')], self::RADIO_VALUE_AUTO, _t('是否解析 [TOC] 语法(符合 HTML 规范,无需 JS 支持)'), _t('开会后支持 [TOC] 语法来生成目录'));
$form->addInput($elementToc);
$elementMermaid = new Form\Element\Radio('is_available_mermaid', [self::RADIO_VALUE_DISABLE => _t('不开启'), self::RADIO_VALUE_AUTO => _t('开启(按需加载)'), self::RADIO_VALUE_FORCE => _t('开启每次加载pjax 主题建议选择此选项)')], self::RADIO_VALUE_AUTO, _t('是否开启 Mermaid 支持(支持自动识别,按需渲染,无需担心引入冗余资源)'), _t('开启后支持解析并渲染 <a href="https://mermaid-js.github.io/mermaid/#/">Mermaid</a>'));
$form->addInput($elementMermaid);
$elementMermaidTheme = new Form\Element\Radio('mermaid_theme', ['default' => _t('默认default'), 'neutral' => _t('墨水neutral'), 'dark' => _t('暗黑dark'), 'forest' => _t('森林绿forest')], 'default', _t('Mermaid 主题颜色'), _t('可以去这里 <a href="https://mermaid.live/edit">实时编辑器</a>调整主题配置看下效果'));
$form->addInput($elementMermaidTheme);
$elementMathJax = new Form\Element\Radio('is_available_mathjax', [self::RADIO_VALUE_DISABLE => _t('不开启'), self::RADIO_VALUE_AUTO => _t('开启(按需加载)'), self::RADIO_VALUE_FORCE => _t('开启每次加载pjax 主题建议选择此选项)')], self::RADIO_VALUE_AUTO, _t('是否开启 MathJax 支持(支持自动识别,按需渲染,无需担心引入冗余资源)'), _t('开启后支持解析并渲染 <a href="https://www.mathjax.org/">MathJax</a>'));
$form->addInput($elementMathJax);
$elementCDNSource = new Form\Element\Radio('cdn_source', array_combine(array_keys(self::CDN_SOURCE_MERMAID), array_map('_t', array_keys(self::CDN_SOURCE_MERMAID))), self::CDN_SOURCE_DEFAULT, _t('静态资源 CDN'), _t('jsDelivr 默认使用最新版本'));
$form->addInput($elementCDNSource);
$elementInternalHosts = new Form\Element\Text('internal_hosts', null, '', _t('设置内部链接'), _t('默认为本站点地址,支持正则表达式("/(^|\.)example\.com$/"),多个可用英文逗号分隔。<br/>外部链接解析策略:默认在新窗口中打开,并加上 "noopener noreferrer" 属性'));
$form->addInput($elementInternalHosts);
$elementHelper = new Form\Element\Radio('show_help_info', [], self::RADIO_VALUE_DISABLE, _t('<a href="https://www.chengxiaobai.cn/php/markdown-parser-library.html/">点击查看更新信息</a>'), _t('<a href="https://www.chengxiaobai.cn/record/markdown-concise-grammar-manual.html/">点击查看语法手册</a>'));
$form->addInput($elementHelper);
}
public static function personalConfig(Form $form)
{
// TODO: Implement personalConfig() method.
}
public static function parse($text)
{
$markdownParser = MarkdownParse::getInstance();
$markdownParser->setIsTocEnable((bool)Options::alloc()->plugin('MarkdownParse')->is_available_toc);
$markdownParser->setInternalHosts((string)Options::alloc()->plugin('MarkdownParse')->internal_hosts ?: parse_url(Options::alloc()->siteUrl, PHP_URL_HOST));
return $markdownParser->parse($text);
}
public static function resourceLink()
{
$markdownParser = MarkdownParse::getInstance();
$configMermaid = (int)Options::alloc()->plugin('MarkdownParse')->is_available_mermaid;
$configLaTex = (int)Options::alloc()->plugin('MarkdownParse')->is_available_mathjax;
$configCDN = (string)Options::alloc()->plugin('MarkdownParse')->cdn_source;
$isAvailableMermaid = $configMermaid === self::RADIO_VALUE_FORCE || ($markdownParser->getIsNeedMermaid() && $configMermaid === self::RADIO_VALUE_AUTO);
$isAvailableMathjax = $configLaTex === self::RADIO_VALUE_FORCE || ($markdownParser->getIsNeedLaTex() && $configLaTex === self::RADIO_VALUE_AUTO);
$resourceContent = '';
if ($isAvailableMermaid) {
$resourceContent .= sprintf('<script type="module">import mermaid from "%s";',self::CDN_SOURCE_MERMAID[$configCDN] ?: self::CDN_SOURCE_MERMAID[self::CDN_SOURCE_DEFAULT]);
$resourceContent .= sprintf('mermaid.initialize({ startOnLoad: true,theme:"%s"});</script>', (string)Options::alloc()->plugin('MarkdownParse')->mermaid_theme ?: 'default');
}
if ($isAvailableMathjax) {
$resourceContent .= '<script type="text/javascript">(function(){MathJax={loader: {load: [\'[tex]/gensymb\']},tex:{inlineMath:[[\'$\',\'$\'],[\'\\\\(\',\'\\\\)\']],packages: {\'[+]\': [\'gensymb\']}}}})();</script>';
$resourceContent .= '<script defer src="https://polyfill.alicdn.com/v3/polyfill.min.js?features=es6"></script>';
$resourceContent .= sprintf('<script id="MathJax-script" defer type="text/javascript" src="%s"></script>', self::CDN_SOURCE_MATHJAX[$configCDN] ?: self::CDN_SOURCE_MATHJAX[self::CDN_SOURCE_DEFAULT]);
}
echo $resourceContent;
}
}

View File

@@ -0,0 +1,70 @@
Markdown Plugin for Typecho
=========================
MarkdownParse 是一款基于 [league/commonmark](https://commonmark.thephpleague.com) 的 Typecho Markdown 解析插件,它的特色在于完美符合 [CommonMark](https://spec.commonmark.org) 和 GFM[GitHub-Flavored Markdown](https://github.github.com/gfm/))规范,不仅可以为你提供强大而丰富的功能,同时也能确保你的内容在不同平台上都能展现一致的出色效果。
本插件除了支持 CommonMark 和 GFM 规范内提到的功能目录、表格、任务列表、脚标等等MarkdownParse 还具有以下额外特性:
1. **Mermaid 语法支持:** 可以利用 Mermaid 语法轻松创建各种图表
2. **MathJax 数学公式渲染:** 支持使用 MathJax 渲染数学公式
3. **智能资源加载:** 根据实际渲染需求,能够智能识别是否加载渲染所需资源,无需担心引入冗余资源
4. **图片延迟加载:** 支持浏览器原生的图片延迟加载技术,[MDN-Lazy loading](https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading)
5. **文本高亮:** 通过 `<mark>` HTML 标签实现文本高亮效果,[MDN-Mark](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark)
## 环境要求
* Typecho 1.2.0 or higher
* PHP 8.1 or higher
## 安装
1. [下载这个插件](https://github.com/mrgeneralgoo/typecho-markdown/releases)
2. 修改文件夹的名字为 "MarkdownParse"
3. 添加到你的项目中并启用它
## 配置页面
![MarkdownParse Config Page](./markdown-parse-config-page.png)
## 报告问题
[你可以直接点击这里提出你的问题](https://github.com/mrgeneralgoo/typecho-markdown/issues/new)
## 语法示例
https://www.chengxiaobai.cn/record/markdown-concise-grammar-manual.html
------
MarkdownParse is a Typecho Markdown parsing plugin based on [league/commonmark](https://commonmark.thephpleague.com). Its feature lies in its perfect compliance with [CommonMark](https://spec.commonmark.org) and GFM ([GitHub-Flavored Markdown](https://github.github.com/gfm/)) specifications. It not only provides you with powerful and abundant functions, but also ensures consistent outstanding effects of your content on different platforms.
In addition to the functions mentioned in the CommonMark and GFM specifications (table of contents, tables, task lists, footnotes, etc.), MarkdownParse also has the following additional features:
1. **Mermaid syntax support:** Easily create various charts using Mermaid syntax
2. **MathJax formula rendering:** Supports rendering mathematical formulas using MathJax
3. **Intelligent resource loading:** According to actual rendering needs, it can intelligently identify whether to load required rendering resources without worrying about introducing redundant resources
4. **Image lazy loading:** Supports native image lazy loading technology in browsers, [MDN-Lazy loading](https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading)
5. **Text highlight:** Realize text highlight effect through `<mark>` HTML tag, [MDN-Mark](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark)
## Requirements
* Typecho 1.2.0 or higher
* PHP 8.1 or higher
## Installation
1. [Download this plugin](https://github.com/mrgeneralgoo/typecho-markdown/releases)
2. Rename the folder to "MarkdownParse"
3. Add it to your project and activate it
## Configuration
![MarkdownParse Config Page](./markdown-parse-config-page.png)
## Reporting Issues
[You can click here directly to create an issue](https://github.com/mrgeneralgoo/typecho-markdown/issues/new)
## Example
https://www.chengxiaobai.cn/record/markdown-concise-grammar-manual.html

Binary file not shown.

Binary file not shown.

64
usr/themes/HarmonyHues/404.php Executable file
View File

@@ -0,0 +1,64 @@
<?php
/**
* 404页面
*
* @author 星语社长
* @link https://biibii.cn
* @update 2024-7-6 18:00:04
*/
if (! defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
?>
<?php $this->need('components/header.php'); ?>
<style>
.error-btn {
color: var(--font-color-main);
background-image: var(--gradient-45deg);
box-shadow: var(--shadow-nav);
border: var(--border-solid-main);
border-radius: var(--border-radius-xlarge);
}
.error-btn:hover {
box-shadow: var(--shadow-inset-box);
}
</style>
<main class="container my-5" style="height: calc(100vh - 260px);">
<div class="card p-4">
<div style="height: 15rem;">
<svg viewBox="0 0 1877 1024" width="100%" height="100%">
<path
d="M1305.6 76.8l42.666667 25.6 69.12-41.813333-58.88 46.933333L1408 136.533333l42.666667-102.4zM1356.8 110.933333v34.133334l18.773333-22.186667z"
fill="#D9D9D9"></path>
<path
d="M1860.266667 909.653333c0 46.933333-403.626667 71.68-911.36 71.68S17.066667 957.44 17.066667 909.653333C17.066667 862.72 431.786667 793.6 939.52 793.6S1860.266667 862.72 1860.266667 909.653333z"
fill="#868DA0"></path>
<path d="M1169.066667 802.133333l-221.866667 162.133334-253.44-165.546667L947.2 785.066667z" fill="#4D4D4D">
</path>
<path
d="M742.4 281.6v477.866667c0 18.773333 15.36 34.133333 34.133333 34.133333h341.333334c18.773333 0 34.133333-15.36 34.133333-34.133333V281.6c0-18.773333-15.36-34.133333-34.133333-34.133333H776.533333c-18.773333 0-34.133333 15.36-34.133333 34.133333z m341.333333 443.733333H810.666667V315.733333h273.066666v409.6z"
fill="#C9CCD6"></path>
<path d="M1160.533333 563.2l-213.333333 93.866667v281.6l213.333333-136.533334z" fill="#BFBFBF">
</path>
<path d="M733.866667 563.2v238.933333l213.333333 136.533334V657.066667L733.866667 563.2z" fill="#A6A6A6">
</path>
<path d="M947.2 657.066667V512l213.333333 51.2z" fill="#737373"></path>
<path
d="M843.093333 762.026667L640 634.026667 733.866667 563.2l213.333333 93.866667zM855.893333 816.64l-3.413333-8.533333-2.56-1.706667-2.56 4.266667s-2.56-4.266667-3.413333-6.826667l-1.706667-0.853333c0 1.706667-0.853333 4.266667-0.853333 4.266666l-1.706667-5.973333-7.68-4.266667-5.973333 2.56-1.706667-6.826666-1.706667 6.826666-3.413333-9.386666-1.706667-0.853334-0.853333 3.413334v6.826666l-1.706667-3.413333-3.413333-9.386667-0.853333-1.706666v62.293333l51.2 34.133333v-67.413333l-2.56-1.706667-3.413334 4.266667zM1051.306667 762.026667l203.093333-128-93.866667-70.826667-213.333333 93.866667z"
fill="#D9D9D9"></path>
<path d="M947.2 657.066667L733.866667 563.2l213.333333-51.2z" fill="#8C8C8C"></path>
<path
d="M188.586667 733.866667H443.733333v136.533333c0 18.773333 15.36 34.133333 34.133334 34.133333s34.133333-15.36 34.133333-34.133333V733.866667h68.266667c18.773333 0 34.133333-15.36 34.133333-34.133334s-15.36-34.133333-34.133333-34.133333h-68.266667V204.8c0-18.773333-15.36-34.133333-34.133333-34.133333s-29.866667 17.066667-29.866667 17.066666l-290.133333 494.08c-9.386667 16.213333-4.266667 36.693333 11.946666 46.933334 9.386667 5.12 18.773333 5.12 18.773334 5.12z m58.026666-68.266667L443.733333 330.24V665.6H246.613333zM1297.92 733.866667H1553.066667v136.533333c0 18.773333 15.36 34.133333 34.133333 34.133333s34.133333-15.36 34.133333-34.133333V733.866667h68.266667c18.773333 0 34.133333-15.36 34.133333-34.133334s-15.36-34.133333-34.133333-34.133333h-68.266667V204.8c0-18.773333-15.36-34.133333-34.133333-34.133333s-29.866667 17.066667-29.866667 17.066666l-290.133333 494.08c-9.386667 16.213333-4.266667 36.693333 11.946667 46.933334 9.386667 5.12 18.773333 5.12 18.773333 5.12z m58.026667-68.266667L1553.066667 330.24V665.6h-197.12z"
fill="#C9CCD6"></path>
</svg>
</div>
<div class="text-center my-4">
<h2>404 - <?php _e('页面没找到'); ?></h2>
<p><?php _e('你想查看的页面已被转移或删除了'); ?></p>
<a class="error-btn d-inline-block my-4 py-2 px-3" href="/" role="button" target="_self"><?php _e('回到首页'); ?></a>
</div>
</div>
</main>
<?php $this->need('components/footer.php'); ?>

View File

@@ -0,0 +1,97 @@
<?php
/**
* 关于主题
*
* @author 星语社长
* @link https://biibii.cn
* @update 2024-12-15 14:46:50
* @package custom
*/
if (!defined('__TYPECHO_ROOT_DIR__')) {
exit;
}
$itemsArray = array(
array('title' => '主题名称', 'content' => $this->title),
array('title' => '主题作者', 'content' => '星语社长'),
array('title' => '主题版本', 'content' => getVersion()),
array('title' => '博客程序', 'content' => 'TYPECHO'),
array('title' => '技术栈', 'content' => 'PHP、HTML、CSS、JS'),
array('title' => '是否开放', 'content' => '<a href="https://github.com/wugeng20/HarmonyHuesTheme" target="_blank" title="HarmonyHues主题">GitHub下载</a>'),
);
$this->need('components/header.php');
?>
<style type="text/css">
.theme-main .theme-cover {
overflow: hidden;
}
.theme-main .theme-text-title {
font-size: 1.5rem;
}
.theme-main .theme-text-content {
font-size: 1.25rem;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
white-space: normal;
}
</style>
<!--主体st-->
<main>
<div class="container theme-main p-2">
<div class="row no-gutters">
<div class="col-lg-12">
<div class="p-1">
<div class="card theme-cover">
<img src="<?php echo getImgLink($this); ?>" class="img-fluid" alt="<?php $this->title() ?>">
</div>
</div>
</div>
<?php foreach ($itemsArray as $item): ?>
<div class="col-6 col-lg-4">
<div class="theme-item p-1">
<div class="d-flex flex-column align-items-center card py-3">
<span class="theme-text-title text-shadow-style font-weight-bold"><?php echo $item['title']; ?></span>
<span class="theme-text-content"><?php echo $item['content']; ?></span>
</div>
</div>
</div>
<?php endforeach; ?>
<div class="col-lg-12">
<!-- 文章内容st -->
<!-- 文章st -->
<div class="p-1 mt-2">
<div class="post card card-body">
<!-- 文章内容 -->
<div class="post-content markdown-body" itemprop="articleBody"><?php $this->content(); ?></div>
<!-- 版权声明 -->
<div class="post-copyright mt-4 p-3">
<div class="copyright-content">
<div class="copyright-title">&#169版权申明</div>
<p class="copyright-desc"><span class="ml-3"></span>- 本文由作者 <a
href="<?php $this->author->permalink(); ?>"
title="<?php $this->author(); ?>">@<?php $this->author(); ?></a>
原创发布在<?php $this->options->title(); ?>站点。未经许可,禁止转载。</p>
</div>
<div class="copyright-svgname">
<?php $this->options->svgName(); ?>
</div>
</div>
</div>
</div>
<!-- 文章en -->
<!--文章评论-->
<?php $this->need('components/comments.php'); ?>
<!-- 文章内容en -->
</div>
</div>
</div>
</main>
<!--主体end-->
<?php $this->need('components/footer.php'); ?>

View File

@@ -0,0 +1,52 @@
# [Typecho Harmony Hues](https://www.biibii.cn/ "Harmony Hues 主题")(和谐色调)主题
![HarmonyHues主题](https://www.biibii.cn/usr/themes/HarmonyHues/assets/images/themeImg.webp)
## 介绍
Typecho 主题-《HarmonyHues - 和谐色调》
- HarmonyHues主题的设计灵感源自自然界中的和谐之美
- 这是一款类拟态风格的主题为什么这样命名因为当时让GPT起几个简洁的主题名称百度翻译一下-和谐色调,然后就选这个,后面才发现,来不及改了...
- 开发主题是为了简洁一点、自己开发能够更好的文章阅读和分享知识!(可以话来点 Star 支持一下)
主题预览链接:[BIIBII.CN](https://www.biibii.cn/)
## 功能
- 自适应布局PC / 移动完美兼容)
- 顶部导航栏多模式切换(全屏沉浸式 / Mini简约式
- 智能主题系统(深色模式 / 浅色模式 / 自动适配系统主题)
- 视觉增强方案:支持图片懒加载 + 点击放大预览Lightbox效果
- SEO优化内置优化策略轻松达成LightHouse 100分评级
- 文章编辑:内置文章内插入视频、网盘下载、提示框、折叠框功能
- 内置插件代码高亮支持多种语言、回复邮件提醒、友情链接、sitemap、表情包等等免插件
- 特色独立页面:我的装备、明信片留言等等
- 特色侧边栏:时间一言、博客路牌、恶魔之眼、最新文章、最新评论等等
- 持续更新支持,更多惊喜等你发现...
## 安装与食用
1. 下载主题压缩包,解压后上传至 Typecho 主题目录(`usr/themes/`
2. 【重要】把解压后的文件夹重命名为 `HarmonyHues`
3. 登录 Typecho 后台,进入外观管理,启用主题即可
4. 进入主题设置,根据需求进行配置
## 预览
| ![HarmonyHues主题-PC端](https://bu.dusays.com/2025/04/16/67ff2ff0c61c9.png) | ![HarmonyHues主题-手机端](https://bu.dusays.com/2025/04/16/67ff2ff0bc3f7.png) |
| ------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
## 联系
- 作者:[星语G.E.N.G](https://www.biibii.cn/about.html)
- 官网:[BIIBII.CN](https://www.biibii.cn/)
- 邮箱:[1431258805@qq.com](mailto:1431258805@qq.com)
- 主题BUG反馈[点击这里](https://www.biibii.cn/bugfeedback.html)
## 捐款
💖 开源之路充满挑战,每一份代码背后都是无数个日夜的坚持。如果您也珍视这个项目带来的价值,诚邀您以捐赠的方式为项目注入成长能量——您的每一份支持都将转化为更优质的功能、更稳定的维护和更长远的发展。
| ![微信捐赠](./assets/images/wechatQr.webp) | ![支付宝捐赠](./assets/images/alipayQr.webp) |
| ---------------------------------------- | ------------------------------------------ |

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,549 @@
@charset "UTF-8";
.markdown-body {
word-break: break-all;
/* table表格样式 */
}
.markdown-body h1 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 2rem;
font-weight: 700;
}
.markdown-body h1::before {
content: "";
position: absolute;
top: 0;
left: -0.15rem;
width: 2rem;
height: 2rem;
background-image: linear-gradient(var(--color-primary-light-2), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0;
}
.markdown-body h1::after {
content: "";
position: absolute;
width: 0.5rem;
height: 0.5rem;
background-image: linear-gradient(var(--color-primary-light-1), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0;
}
.markdown-body h1:hover::before {
transform: scale(1.5);
}
.markdown-body h2 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 1.5rem;
font-weight: 700;
}
.markdown-body h2::before {
content: "";
position: absolute;
top: 0;
left: -0.15rem;
width: 1.75rem;
height: 1.75rem;
background-image: linear-gradient(var(--color-primary-light-2), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0;
}
.markdown-body h2::after {
content: "";
position: absolute;
width: 0.4375rem;
height: 0.4375rem;
background-image: linear-gradient(var(--color-primary-light-1), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0;
}
.markdown-body h2:hover::before {
transform: scale(1.5);
}
.markdown-body h3 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 1.25rem;
font-weight: 700;
}
.markdown-body h3::before {
content: "";
position: absolute;
top: 0;
left: -0.15rem;
width: 1.25rem;
height: 1.25rem;
background-image: linear-gradient(var(--color-primary-light-2), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0.25rem;
}
.markdown-body h3::after {
content: "";
position: absolute;
width: 0.3125rem;
height: 0.3125rem;
background-image: linear-gradient(var(--color-primary-light-1), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0;
}
.markdown-body h3:hover::before {
transform: scale(1.5);
}
.markdown-body h4 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 1.125rem;
font-weight: 700;
}
.markdown-body h5 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 1rem;
font-weight: 700;
}
.markdown-body h6 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 0.875rem;
font-weight: 700;
}
.markdown-body p {
margin: 0;
font-size: 1rem;
line-height: 1.7;
}
.markdown-body a:not([data-fancybox]):not([data-links]):not([data-cloud]) {
color: var(--color-primary);
padding: 0 0.15rem;
outline: 0;
text-decoration: underline dotted 0.2ex;
text-decoration-skip-ink: none;
text-underline-offset: 0.5ex;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
background: linear-gradient(var(--color-primary-light-5), var(--color-primary-light-5)) no-repeat bottom/100% 0;
transition: background .3s;
}
.markdown-body a:not([data-fancybox]):not([data-links]):not([data-cloud]):hover {
text-decoration: underline;
background-size: 100% 100%;
}
.markdown-body blockquote,
.markdown-body details,
.markdown-body dl,
.markdown-body ol,
.markdown-body pre,
.markdown-body table,
.markdown-body ul {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 2rem;
line-height: 1.7;
}
.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ul,
.markdown-body ol ol {
margin: 0;
padding-left: 1rem;
}
.markdown-body ol {
list-style-type: decimal;
}
.markdown-body ul {
list-style-type: disc;
}
.markdown-body img {
display: block;
max-width: 100%;
height: auto;
margin: auto;
margin-top: 0.25rem;
margin-bottom: 0.25rem;
border-radius: var(--border-radius-base);
object-fit: cover;
cursor: zoom-in;
cursor: -webkit-zoom-in;
border: var(--border-solid-small);
}
.markdown-body img.emoji-image {
display: inline-block;
width: 1.25rem;
height: 1.25rem;
margin: 0;
border: none;
}
.markdown-body blockquote {
position: relative;
padding: 2rem;
line-height: 1.8;
text-indent: 0;
color: var(--font-color-main-transparent);
border: var(--border-solid-small);
border-radius: var(--border-radius-base);
overflow: hidden;
}
.markdown-body blockquote:before, .markdown-body blockquote:after {
position: absolute;
font-family: Arial, serif;
font-size: 4rem;
font-weight: 700;
color: var(--border-color-main);
}
.markdown-body blockquote:before {
content: "“";
left: 1rem;
top: -1.5rem;
}
.markdown-body blockquote:after {
content: "”";
right: 1rem;
bottom: -3rem;
}
.markdown-body table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.markdown-body table th,
.markdown-body table td {
padding: 0.5rem 1rem;
border-right: 1px solid rgba(230, 230, 240, 0.75);
border-top: 1px solid rgba(230, 230, 240, 0.75);
letter-spacing: 0;
text-align: left;
vertical-align: top;
}
.markdown-body table tr:nth-child(odd) {
background-color: var(--overlay-color-light-1);
}
.markdown-body table tr:nth-child(even) {
background-color: var(--overlay-color-light-8);
}
.markdown-body table tr:last-child th:first-child {
border-left: 1px solid rgba(230, 230, 240, 0.75);
border-top-left-radius: var(--border-radius-medium);
}
.markdown-body table tr:last-child th:last-child {
border-top-right-radius: var(--border-radius-medium);
}
.markdown-body table tr:last-child td {
border-bottom: 1px solid rgba(230, 230, 240, 0.75);
}
.markdown-body table tr:last-child td:first-child {
border-bottom-left-radius: var(--border-radius-medium);
}
.markdown-body table tr:last-child td:last-child {
border-bottom-right-radius: var(--border-radius-medium);
}
.markdown-body table tr th {
background-color: var(--bg-color-main-dark);
color: var(--bg-color-main);
}
.markdown-body table tr td:first-child {
border-left: 1px solid rgba(230, 230, 240, 0.75);
}
.markdown-body code:not([class^="lang-"]):not([class^="language-"]) {
border-radius: 0.2rem;
background-color: var(--color-primary-light-4);
color: var(--color-primary);
font-size: 1rem;
padding: 0.15rem 0.3rem;
margin: 0 2px;
}
.markdown-body .pre-container {
position: relative;
border: var(--border-solid-small);
border-radius: var(--border-radius-medium);
overflow: hidden;
}
.markdown-body .pre-container .pre-header {
position: relative;
background-color: var(--bg-color-main);
}
.markdown-body .pre-container .pre-header .pre-icon::before {
display: inline-block;
content: '';
width: 12px;
height: 12px;
border-radius: var(--border-radius-circle);
background: #fc625d;
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
z-index: 1;
}
.markdown-body .pre-container .pre-header .pre-copy {
font-size: 0.85rem;
background-color: transparent;
}
.markdown-body .pre-container pre {
position: relative;
margin: 0;
border-radius: unset;
max-height: 30rem;
}
.markdown-body .pre-container pre code {
font-size: 1rem;
}
.markdown-body .pre-container pre::-webkit-scrollbar {
width: 4px !important;
height: 4px !important;
-webkit-appearance: none;
appearance: none;
}
.markdown-body hr {
border: 0;
padding: 0.15rem;
background: repeating-linear-gradient(135deg, var(--border-color-main) 0px, var(--font-color-main-transparent) 1px, transparent 1px, transparent 6px);
}
.markdown-body video {
max-width: 100%;
height: auto;
vertical-align: middle;
border-radius: var(--border-radius-medium);
border: var(--border-solid-small);
}
.markdown-body iframe {
max-width: 100%;
height: auto;
vertical-align: middle;
border-radius: var(--border-radius-base);
}
/* 短代码样式一些公共样式 */
.short-code-card {
position: relative;
gap: 1rem;
color: var(--font-color-main);
text-decoration: none;
width: 20rem;
max-width: 100%;
min-height: 4rem;
overflow: hidden;
margin: 1rem auto;
z-index: 1;
overflow: hidden;
background: var(--gradient-45deg);
border-radius: var(--border-radius-medium);
box-shadow: var(--shadow-box-small);
border: var(--border-solid-small);
}
.short-code-card:hover {
box-shadow: var(--shadow-inset-box);
}
.short-code-card img,
.short-code-card svg {
width: 4rem;
height: 4rem;
margin: 0;
box-shadow: var(--shadow-nav);
}
/* 短代码-文章Hint样式 */
.hint-content {
--hint-color: var(--success);
--hint-bg: #e1efe5;
position: relative;
display: flex;
flex-direction: row;
gap: 0.5rem;
color: var(--hint-color);
border: 1px solid var(--hint-bg);
border-radius: var(--border-radius-base);
background-color: var(--hint-bg);
transition: all 0.3s ease-in-out;
overflow: hidden;
margin: 0.5rem 0;
}
.hint-content .iconfont {
line-height: 2;
color: var(--hint-color);
vertical-align: middle;
}
.hint-content.hint-info {
--hint-color: var(--font-color-main);
--hint-bg: #eee;
}
.hint-content.hint-warning {
--hint-color: var(--warning);
--hint-bg: #fff7dc;
}
.hint-content.hint-danger {
--hint-color: var(--red);
--hint-bg: #ffeaec;
}
.hint-content:hover {
transform: translateY(-5px);
}
/* 短代码-文章链接样式 */
.to-links-content {
position: relative;
}
.to-links-content a .to-links-text span {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
}
.to-links-content a .to-links-url,
.to-links-content a .icon-lianjie {
color: var(--font-color-muted);
}
/* 短代码-网盘下载样式 */
.cloud-download-box {
position: relative;
}
.cloud-download-box .cloud-download-icon {
flex-shrink: 0;
background-color: var(--bg-color-main);
border-radius: var(--border-radius-medium);
overflow: hidden;
}
.cloud-download-box .cloud-download-info {
width: 100%;
}
.cloud-download-box .cloud-download-info .cloud-download-title a {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
}
.cloud-download-box .cloud-download-info .cloud-download-password {
display: inline-block;
color: var(--font-color-main-light);
}
.cloud-download-box .cloud-download-info .cloud-download-btn span {
color: var(--font-color-main-transparent);
font-size: 0.8rem;
}
.cloud-download-box .cloud-download-info .cloud-download-btn a {
background-color: var(--bg-color-primary);
border-radius: var(--border-radius-medium);
}
/* 折叠框样式 */
.fold-container {
position: relative;
overflow: hidden;
border: var(--border-solid-small);
background: var(--gradient-45deg);
border-radius: var(--border-radius-medium);
}
.fold-container .fold-header {
cursor: pointer;
user-select: none;
background: var(--widget-bg-gradient);
}
.fold-container .fold-header::after {
content: "+";
font-size: 1.25rem;
line-height: 1;
float: right;
}
.fold-container[open] .fold-header::after {
content: "-";
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,506 @@
// 变量
$base-size: 0.25rem;
$base-margin: 1rem;
$base-font-size: 1rem;
$base-line-height: 1.7;
$base-font-weight: 700;
$border-base: 1px solid rgba(230, 230, 240, .75);
// 定义一个 mixin 用于设置标题的公共样式
@mixin heading-styles($size) {
position: relative;
margin-top: $base-margin;
margin-bottom: $base-margin;
font-size: $size * $base-font-size;
font-weight: $base-font-weight;
}
// 定义一个 mixin 用于设置标题前的装饰元素
@mixin heading-decoration($width, $height, $bottom: 0) {
&::before {
content: "";
position: absolute;
top: 0;
left: -0.15rem;
width: $width;
height: $height;
background-image: linear-gradient(var(--color-primary-light-2), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: $bottom;
}
&::after {
content: "";
position: absolute;
width: $width / 4;
height: $height / 4;
background-image: linear-gradient(var(--color-primary-light-1), transparent);
opacity: .5;
border-radius: var(--border-radius-circle);
transition: all .3s;
z-index: -1;
bottom: 0;
}
&:hover::before {
transform: scale(1.5);
}
}
.markdown-body {
word-break: break-all; // 英文单词换行
// h标签
h1 {
@include heading-styles(2);
@include heading-decoration($base-size * 8, $base-size * 8);
}
h2 {
@include heading-styles(1.5);
@include heading-decoration($base-size * 7, $base-size * 7);
}
h3 {
@include heading-styles(1.25);
@include heading-decoration($base-size * 5, $base-size * 5, $base-size);
}
h4 {
@include heading-styles(1.125);
}
h5 {
@include heading-styles(1);
}
h6 {
@include heading-styles(0.875);
}
// p标签
p {
margin: 0;
font-size: $base-font-size;
line-height: $base-line-height;
}
// 链接a标签
a:not([data-fancybox]):not([data-links]):not([data-cloud]) {
color: var(--color-primary);
padding: 0 0.15rem;
outline: 0;
text-decoration: underline dotted 0.2ex;
text-decoration-skip-ink: none;
text-underline-offset: 0.5ex;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
background: linear-gradient(var(--color-primary-light-5), var(--color-primary-light-5)) no-repeat bottom/100% 0;
transition: background .3s;
&:hover {
text-decoration: underline;
background-size: 100% 100%;
}
}
blockquote,
details,
dl,
ol,
pre,
table,
ul {
margin-top: $base-size * 2;
margin-bottom: $base-size * 2;
}
// ul/ol标签
ul,
ol {
padding-left: $base-size * 8;
line-height: $base-line-height;
ul,
ol {
margin: 0;
padding-left: $base-size * 4;
}
}
ol {
list-style-type: decimal;
}
ul {
list-style-type: disc;
}
// 图片img标签
img {
display: block;
max-width: 100%;
height: auto;
margin: auto;
margin-top: $base-size;
margin-bottom: $base-size;
border-radius: var(--border-radius-base);
object-fit: cover;
cursor: zoom-in;
cursor: -webkit-zoom-in;
border: var(--border-solid-small);
&.emoji-image {
display: inline-block;
width: 1.25rem;
height: 1.25rem;
margin: 0;
border: none;
}
}
// 引用blockquote标签
blockquote {
position: relative;
padding: $base-size * 8;
line-height: 1.8;
text-indent: 0;
color: var(--font-color-main-transparent);
border: var(--border-solid-small);
border-radius: var(--border-radius-base);
overflow: hidden;
&:before,
&:after {
position: absolute;
font-family: Arial, serif;
font-size: $base-font-size * 4;
font-weight: $base-font-weight;
color: var(--border-color-main);
}
&:before {
content: "";
left: 1rem;
top: -1.5rem;
}
&:after {
content: "";
right: 1rem;
bottom: -3rem;
}
}
/* table表格样式 */
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
th,
td {
padding: $base-size * 2 $base-size * 4;
border-right: $border-base;
border-top: $border-base;
letter-spacing: 0;
text-align: left;
vertical-align: top;
}
tr {
&:nth-child(odd) {
background-color: var(--overlay-color-light-1);
}
&:nth-child(even) {
background-color: var(--overlay-color-light-8);
}
&:last-child {
th {
&:first-child {
border-left: $border-base;
border-top-left-radius: var(--border-radius-medium);
}
&:last-child {
border-top-right-radius: var(--border-radius-medium);
}
}
td {
border-bottom: $border-base;
&:first-child {
border-bottom-left-radius: var(--border-radius-medium);
}
&:last-child {
border-bottom-right-radius: var(--border-radius-medium);
}
}
}
th {
background-color: var(--bg-color-main-dark);
color: var(--bg-color-main);
}
td {
&:first-child {
border-left: $border-base;
}
}
}
}
// 代码code标签
code:not([class^="lang-"]):not([class^="language-"]) {
border-radius: 0.2rem;
background-color: var(--color-primary-light-4);
color: var(--color-primary);
font-size: $base-font-size;
padding: 0.15rem 0.3rem;
margin: 0 2px;
}
// 代码pre标签
.pre-container {
position: relative;
border: var(--border-solid-small);
border-radius: var(--border-radius-medium);
overflow: hidden;
.pre-header {
position: relative;
background-color: var(--bg-color-main);
.pre-icon::before {
display: inline-block;
content: '';
width: 12px;
height: 12px;
border-radius: var(--border-radius-circle);
background: #fc625d;
box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b;
z-index: 1;
}
.pre-copy {
font-size: 0.85rem;
background-color: transparent;
}
}
pre {
position: relative;
margin: 0;
border-radius: unset;
max-height: $base-size * 120;
code {
font-size: $base-font-size;
}
&::-webkit-scrollbar {
width: 4px !important;
height: 4px !important;
-webkit-appearance: none;
appearance: none;
}
}
}
// hr标签
hr {
border: 0;
padding: 0.15rem;
background: repeating-linear-gradient(135deg, var(--border-color-main) 0px, var(--font-color-main-transparent) 1px, transparent 1px, transparent 6px);
}
// 视频video标签
video {
max-width: 100%;
height: auto;
vertical-align: middle;
border-radius: var(--border-radius-medium);
border: var(--border-solid-small);
}
// iframe标签
iframe {
max-width: 100%;
height: auto;
vertical-align: middle;
border-radius: var(--border-radius-base);
}
}
/* 短代码样式一些公共样式 */
.short-code-card {
position: relative;
gap: 1rem;
color: var(--font-color-main);
text-decoration: none;
width: 20rem;
max-width: 100%;
min-height: 4rem;
overflow: hidden;
margin: 1rem auto;
z-index: 1;
overflow: hidden;
background: var(--gradient-45deg);
border-radius: var(--border-radius-medium);
box-shadow: var(--shadow-box-small);
border: var(--border-solid-small);
&:hover {
box-shadow: var(--shadow-inset-box);
}
img,
svg {
width: 4rem;
height: 4rem;
margin: 0;
box-shadow: var(--shadow-nav);
}
}
/* 短代码-文章Hint样式 */
.hint-content {
--hint-color: var(--success);
--hint-bg: #e1efe5;
position: relative;
display: flex;
flex-direction: row;
gap: 0.5rem;
color: var(--hint-color);
border: 1px solid var(--hint-bg);
border-radius: var(--border-radius-base);
background-color: var(--hint-bg);
transition: all 0.3s ease-in-out;
overflow: hidden;
margin: 0.5rem 0;
// 图标样式
.iconfont {
line-height: 2;
color: var(--hint-color);
vertical-align: middle;
}
// 不同类型提示框的样式
&.hint-info {
--hint-color: var(--font-color-main);
--hint-bg: #eee;
}
&.hint-warning {
--hint-color: var(--warning);
--hint-bg: #fff7dc;
}
&.hint-danger {
--hint-color: var(--red);
--hint-bg: #ffeaec;
}
// 鼠标悬停效果
&:hover {
transform: translateY(-5px);
}
}
/* 短代码-文章链接样式 */
.to-links-content {
position: relative;
a {
.to-links-text span {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
}
.to-links-url,
.icon-lianjie {
color: var(--font-color-muted);
}
}
}
/* 短代码-网盘下载样式 */
.cloud-download-box {
position: relative;
.cloud-download-icon {
flex-shrink: 0;
background-color: var(--bg-color-main);
border-radius: var(--border-radius-medium);
overflow: hidden;
}
.cloud-download-info {
width: 100%;
.cloud-download-title a {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
word-break: break-all;
}
.cloud-download-password {
display: inline-block;
color: var(--font-color-main-light);
}
.cloud-download-btn span {
color: var(--font-color-main-transparent);
font-size: 0.8rem;
}
.cloud-download-btn a {
background-color: var(--bg-color-primary);
border-radius: var(--border-radius-medium);
}
}
}
/* 折叠框样式 */
.fold-container {
position: relative;
overflow: hidden;
border: var(--border-solid-small);
background: var(--gradient-45deg);
border-radius: var(--border-radius-medium);
.fold-header {
cursor: pointer;
user-select: none;
background: var(--widget-bg-gradient);
&::after {
content: "+";
font-size: 1.25rem;
line-height: 1;
float: right;
}
}
&[open] .fold-header::after {
content: "-";
}
}

View File

@@ -0,0 +1,551 @@
@charset "UTF-8";
/* ------------------------------------ Harmony Hues主题 @author 星语社长 @link https://biibii.cn @update 2024-7-6 18:00:04 --------------------------------- */
:root { /*基础样式*/ font-synthesis: style; -webkit-text-size-adjust: none; -moz-text-size-adjust: none; text-size-adjust: none; word-wrap: break-word; color: var(--font-color-main); /* 色调 */ /* 主色调:现代蓝色 */ --color-primary: #165DFF; /* 比主色调更深 */ --color-primary-dark-1: #0E42D2; /* 更深的色调 */ --color-primary-dark-2: #072A8A; /* 非常深的色调 */ --color-primary-dark-3: #041957; /* 比主色调稍浅 */ --color-primary-light-1: #4080FF; /* 浅一些的色调 */ --color-primary-light-2: #6AA1FF; /* 较浅的色调 */ --color-primary-light-3: #94BFFF; /* 更浅的色调 */ --color-primary-light-4: #BEDAFF; /* 非常浅的色调 */ --color-primary-light-5: #E8F3FF; /* 主背景色 */ --bg-color-main: #fff; /* 主背景色-黑 */ --bg-color-main-dark: #000; /* 页面背景色 */ --bg-color-body: #f6f7f9; /* 遮罩层浅色1 */ --overlay-color-light-1: rgba(255, 255, 255, 0.1); /* 遮罩层浅色2 */ --overlay-color-light-2: rgba(255, 255, 255, 0.2); /* 遮罩层浅色3 */ --overlay-color-light-3: rgba(255, 255, 255, 0.3); /* 遮罩层浅色4 */ --overlay-color-light-4: rgba(255, 255, 255, 0.4); /* 遮罩层浅色5 */ --overlay-color-light-5: rgba(255, 255, 255, 0.5); /* 遮罩层浅色8 */ --overlay-color-light-8: rgba(255, 255, 255, 0.8); /* 黑遮罩层浅色1 */ --overlay-color-dark-1: rgba(0, 0, 0, 0.1); /* 黑遮罩层浅色2 */ --overlay-color-dark-2: rgba(0, 0, 0, 0.2); /* 黑遮罩层浅色3 */ --overlay-color-dark-3: rgba(0, 0, 0, 0.3); /* 黑遮罩层浅色4 */ --overlay-color-dark-4: rgba(0, 0, 0, 0.4); /* 黑遮罩层浅色5 */ --overlay-color-dark-5: rgba(0, 0, 0, 0.5); /* 主字体颜色 */ --font-color-main: #333; /* 主字体颜色(浅色) */ --font-color-main-light: #6c757d; /* 主字体颜色(透明) */ --font-color-main-transparent: rgba(60, 60, 60, 0.7); /* 字体颜色muted */ --font-color-muted: #b2b2b2; /* 主边框颜色 */ --border-color-main: #e4e4e4; /* 主要背景色 */ --bg-color-primary: #f2f2f2; /* 次要背景色 */ --bg-color-secondary: #f5f5f5; /* 基础圆角大小 */ --border-radius-base: 8px; /* 小圆角大小 */ --border-radius-small: 5px; /* 中等圆角大小 */ --border-radius-medium: calc(var(--border-radius-small) * 2); /* 大圆角大小 */ --border-radius-large: calc(var(--border-radius-small) * 6); /* 超大圆角大小 */ --border-radius-xlarge: calc(var(--border-radius-small) * 20); /* 圆形圆角 */ --border-radius-circle: 50%; /* 固定导航栏高度 */ --height-nav-fixed: 80px; /* 页脚高度 */ --height-footer: 60px; /* 主背景滤镜 */ --backdrop-filter-main: saturate(180%) blur(20px); /* 主渐变透明背景 */ --gradient-primary-transparent: linear-gradient(0deg, var(--color-primary-light-4), transparent); /* 主题样式 */ /* 中等蓝色灰色 */ --color-blue-gray-medium: var(--color-primary); /* 浅色中等蓝色灰色 */ --color-blue-gray-medium-light: var(--color-primary-dark-3); /* 主阴影 */ --shadow-box-main: 8px 8px 15px 0 rgba(55, 99, 170, 0.1), -8px -8px 15px 0 var(--bg-color-main), inset 0 4px 15px 0 var(--overlay-color-light-5); /* 小阴影 */ --shadow-box-small: 5px 5px 12px 0 rgba(55, 99, 170, 0.1), -5px -5px 12px 0 var(--bg-color-main), inset 0 4px 10px 0 var(--overlay-color-light-5); /* 悬停阴影 */ --shadow-box-hover: 8px 8px 15px 0 rgba(55, 99, 170, 0.2), -8px -8px 15px 0 var(--bg-color-main); /* 0度渐变 */ --gradient-0deg: linear-gradient(0deg, var(--bg-color-body), #f8f8f8); /* 45度渐变 */ --gradient-45deg: linear-gradient(45deg, var(--bg-color-body), #f8f8f8); /* 工具背景渐变 */ --widget-bg-gradient: linear-gradient(-45deg, var(--bg-color-main), #f3f5f8); /* 主边框 */ --border-solid-main: 2px solid var(--bg-color-main); /* 小边框 */ --border-solid-small: 1px solid var(--bg-color-main); /* 导航栏阴影 */ --shadow-nav: 0 5px 12px 0 rgba(50, 98, 170, 0.1); /* 导航栏shadow */ --shadow-hover-nav: inset -8px -8px 16px var(--bg-color-body), inset 8px 8px 16px var(--bg-color-body), 8px 8px 16px rgba(0, 0, 0, 0.25); /* 内嵌阴影 */ --shadow-inset-box: inset -4px -4px 12px #f1f1f1, inset 4px 4px 12px #e2e2e2; /* 所有属性过渡效果 */ --transition-ease-all: all .3s ease 0s; }
:root[data-theme=dark] { --bg-color-main: #262626; --bg-color-main-dark: #fff; --bg-color-body: #222222; --overlay-color-light-1: rgba(0, 0, 0, 0.5); --overlay-color-light-2: #333333; --overlay-color-light-3: #4d4d4d; --overlay-color-light-4: #666666; --overlay-color-light-5: #2a2a2a; --overlay-color-light-8: #2e2e2e; --overlay-color-dark-1: #4d4d4d; --overlay-color-dark-2: rgba(255, 255, 255, 0.25); --overlay-color-dark-3: #808080; --overlay-color-dark-4: #999999; --overlay-color-dark-5: #b3b3b3; --font-color-main: #fff; --font-color-main-light: #b3b3b3; --font-color-main-transparent: rgba(220, 220, 220, 0.7); --font-color-muted: #757575; --border-color-main: #333; --bg-color-primary: #2C2C2C; --bg-color-secondary: #171717; --gradient-primary-transparent: linear-gradient(0deg, #333, rgba(0, 0, 0, 0.3)); --color-blue-gray-medium: var(--color-primary); --color-blue-gray-medium-light: var(--color-primary-dark-3); --shadow-box-main: 8px 8px 15px 0 rgba(0, 0, 0, 0.3), -8px -8px 15px 0 var(--bg-color-main), inset 0 4px 15px 0 var(--bg-color-body); --shadow-box-small: 5px 5px 12px 0 rgba(0, 0, 0, 0.3), -5px -5px 12px 0 var(--bg-color-main), inset 0 4px 10px 0 var(--bg-color-body); --shadow-box-hover: 8px 8px 15px 0 rgba(0, 0, 0, 0.4), -8px -8px 15px 0 var(--bg-color-main); --gradient-0deg: linear-gradient(0deg, var(--bg-color-body), var(--overlay-color-light-5)); --gradient-45deg: linear-gradient(45deg, var(--bg-color-body), var(--overlay-color-light-5)); --widget-bg-gradient: linear-gradient(-45deg, var(--bg-color-main), var(--bg-color-body)); --shadow-nav: 0 5px 12px 0 rgba(0, 0, 0, 0.3); --shadow-inset-box: inset -4px -4px 12px #1a1a1a, inset 4px 4px 12px #1e1e1e; }
/* 全局样式 */
html { scroll-behavior: smooth; }
body { background-color: var(--bg-color-body) !important; }
ol, ul { list-style: none; margin: 0; }
*, *::before, *::after { font: inherit; color: inherit; padding: 0; margin: 0; border: 0; outline: 0; vertical-align: baseline; box-sizing: border-box; scroll-behavior: smooth; }
/* 去除a标签默认样式 */
a { color: var(--font-color-main); cursor: pointer; text-decoration: none; transition: color 0.3s ease; }
a:link, a:visited, a:hover, a:active, a:focus { text-decoration: none; }
a:hover { color: var(--color-blue-gray-medium) !important; }
/*--------浏览器滚动条---------*/
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
::-webkit-scrollbar { -webkit-appearance: none; width: 0.5rem; height: 0.5rem; }
/*定义滚动条轨道 内阴影+圆角*/
::-webkit-scrollbar-track { background-color: #e4e4e4; }
/*定义滑块 内阴影+圆角*/
::-webkit-scrollbar-thumb { cursor: pointer; border-radius: 10px; background: #b2b2b2; -webkit-transition: color .3s ease; transition: color .3s ease; }
/* 指定滚动样式 */
.scroll-cover { overflow: auto; }
.scroll-cover::-webkit-scrollbar { width: 2px !important; height: 2px !important; -webkit-appearance: none; appearance: none; }
.scroll-cover::-webkit-scrollbar-track { background-color: transparent; }
/*--------浏览器滚动条---------*/
/*---输入公共样式---*/
input, textarea, select { color: var(--font-color-main) !important; box-shadow: var(--shadow-inset-box) !important; background-color: transparent !important; border-radius: var(--border-radius-base) !important; border: var(--border-solid-small) !important; }
@media (max-width: 767.98px) { input, textarea, select { border: var(--border-solid-small) !important; } }
input:-webkit-autofill { transition: background-color 5000s ease-in-out 0s; -webkit-text-fill-color: var(--font-color-main) !important; }
button { color: var(--font-color-main) !important; }
button.btn:focus { box-shadow: var(--shadow-inset-box); }
img, video { width: 100%; height: 100%; object-fit: cover; }
:root[data-theme=dark] img, :root[data-theme=dark] video { filter: brightness(0.85); }
/* 名字svg样式 */
.svg-name path { fill: var(--font-color-main); }
/* 文字边框 */
.title-text-stroke { text-stroke: 1px var(--font-color-main); -webkit-text-stroke: 1px var(--font-color-main); -webkit-text-fill-color: transparent; }
/* 文字阴影 */
.text-shadow-style { position: relative; --text-col: var(--bg-color-main); --text-show-col: var(--font-color-main); color: var(--text-col); text-shadow: 3px 3px 0 var(--text-show-col), -1px -1px 0 var(--text-show-col), 1px -1px 0 var(--text-show-col), -1px 1px 0 var(--text-show-col), 1px 1px 0 var(--text-show-col); }
.text-webkit-mask { opacity: 0.5; -webkit-mask: linear-gradient(var(--bg-color-main) 50%, transparent); mask: linear-gradient(var(--bg-color-main) 50%, transparent); }
/* 图标公共样式 */
.iconfont { font-family: "iconfont" !important; color: var(--font-color-main); font-size: 1.5rem; font-style: normal; line-height: 1; -webkit-font-smoothing: antialiased; -webkit-text-stroke-width: 0.2px; -moz-osx-font-smoothing: grayscale; }
.iconfont:hover { color: var(--color-blue-gray-medium); }
/* 公共动画 */
@keyframes fade-in-top { from { opacity: 0;
transform: translateY(15px); }
to { opacity: 1;
transform: translateY(0); } }
@-webkit-keyframes fade-in-top { from { opacity: 0;
-webkit-transform: translateY(15px); }
to { opacity: 1;
-webkit-transform: translateY(0); } }
.animated-signature path { stroke-dasharray: 2400; stroke-dashoffset: 2400; fill: transparent; animation: drawSignature 8s linear infinite both; -webkit-animation: drawSignature 8s linear infinite both; stroke-width: 2px; stroke: var(--font-color-main); }
img.lazy { background-color: var(--color-primary-light-5); filter: blur(25px); -webkit-transition: opacity 1s ease-in-out; transition: opacity 1s ease-in-out; }
img.loaded { background-color: transparent; filter: blur(0px); -webkit-transition: filter 1s linear, -webkit-filter 1s linear; transition: filter 1s linear, -webkit-filter 1s linear; }
@keyframes drawSignature { 0% { stroke-dashoffset: 2400; }
15% { fill: transparent; }
35%, 75% { stroke-dashoffset: 0;
fill: var(--font-color-main); }
90%, to { stroke-dashoffset: 2400;
fill: transparent; } }
.view-image-lead img { width: auto; height: auto; }
/*---------- 导航栏样式st ----------*/
/* 导航栏样式 */
.navbar { position: fixed; z-index: 99; width: 100%; background-color: transparent; transition: var(--transition-ease-all); }
.navbar.nav-ui-one { background-image: radial-gradient(transparent 1px, var(--bg-color-main) 1px); background-size: 4px 4px; -webkit-backdrop-filter: saturate(50%) blur(5px); backdrop-filter: saturate(50%) blur(5px); -webkit-box-shadow: var(--shadow-nav) !important; box-shadow: var(--shadow-nav) !important; }
.navbar.nav-ui-two .navbar-box { background-image: radial-gradient(transparent 1px, var(--bg-color-main) 1px); background-size: 4px 4px; -webkit-backdrop-filter: saturate(50%) blur(5px); backdrop-filter: saturate(50%) blur(5px); -webkit-box-shadow: var(--shadow-nav) !important; box-shadow: var(--shadow-nav) !important; border: var(--border-solid-main); border-radius: var(--border-radius-medium); }
.navbar.active { box-shadow: var(--shadow-nav) !important; }
.navbar.nav-hidden { transform: translateY(-100%) !important; opacity: 0 !important; }
.navbar.nav-visible { transform: translateY(0) !important; opacity: 1 !important; }
.navbar-logo span { font-size: 1.5rem; }
.navbar-logo img { height: 40px; }
.nav-inner { position: relative; }
.nav-inner .nav-icon { display: inline-block; margin-left: 0.1rem; font-size: 0.8rem; transition: transform 0.3s; }
.nav-inner .nav-menu { gap: 1rem; }
.nav-inner .nav-item { position: relative; }
.nav-inner .nav-item .nav-a.active { color: var(--color-primary); text-shadow: 0 0.15rem 1rem var(--color-primary-light-1); }
.nav-inner .nav-item .nav-a.active .nav-icon { color: var(--color-blue-gray-medium); }
.nav-inner .nav-item > .sub-menu { position: absolute; left: -15%; opacity: 0; visibility: hidden; pointer-events: none; z-index: 9; transform: translateY(-15px); transition: all 0.3s ease; }
.nav-inner .nav-item:hover .nav-a { color: var(--color-blue-gray-medium); }
.nav-inner .nav-item:hover > .sub-menu { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0); }
.nav-inner .nav-item:hover .nav-icon { color: var(--color-blue-gray-medium); transform: rotate(-90deg); }
.nav-inner .sub-menu { white-space: nowrap; }
.nav-inner .sub-menu ul { background: var(--gradient-0deg); border-radius: var(--border-radius-base); white-space: nowrap; border: var(--border-solid-main); box-shadow: var(--shadow-hover-nav); overflow: hidden; }
.nav-inner .sub-menu ul li { position: relative; width: 100%; transition: all .3s; overflow: hidden; }
.nav-inner .sub-menu ul li > a { --nav-font-size: 20px; display: inline-block; transform: translateY(calc(-1 * var(--nav-font-size) * 1.5)); text-shadow: 0px calc(var(--nav-font-size) * 1.5) 0px var(--font-color-main); transition: transform 0.3s cubic-bezier(0.15, 1, 0.35, 1); }
.nav-inner .sub-menu ul li:hover > a { transform: translateY(0); }
.nav-inner .sub-menu ul li:hover, .nav-inner .sub-menu ul li.active { width: 100%; background-color: var(--bg-color-main); border-radius: var(--border-radius-medium); box-shadow: var(--shadow-box-hover); }
.navbar-icon { gap: 1rem; }
@media (max-width: 767.98px) { .navbar-icon { gap: 0.5rem; } }
.navbar-icon .iconfont { font-size: 1.35rem; }
/*滚动进度+回到顶部样式*/
.back-to-top { display: flex; overflow: hidden; }
.back-to-top .nav-top-item { text-align: center; font-size: 0.8rem; width: 1.6rem; height: 1.6rem; line-height: 1.6rem; border-radius: var(--border-radius-xlarge); background: var(--font-color-main); color: var(--bg-color-main); transition: width 0.3s, display 0.3s; }
.back-to-top .nav-top-item.top-to-active { width: 5rem; }
.back-to-top .top-to-icon { display: none; }
.back-to-top:hover .top-to-icon { display: inline-block; }
.back-to-top:hover .top-to-text { display: none; }
.back-to-top:hover .nav-top-item { width: 5rem; }
/* ----》手机导航栏菜单 */
#nav-components.mobile-aside { display: flex; flex-direction: column; position: fixed; width: 100%; max-height: 95vh; min-height: 70vh; opacity: 0; visibility: hidden; background-color: var(--bg-color-main); bottom: 0; z-index: 1000; transform: translateY(100%); transition: transform 1s cubic-bezier(0.3, 0.7, 0, 1), opacity 1s linear, visibility 1s linear; border-top-left-radius: var(--border-radius-medium); border-top-right-radius: var(--border-radius-medium); box-shadow: 0 -0.15rem 1.5rem 0.25rem var(--overlay-color-dark-1); }
#nav-components.mobile-aside.open { visibility: visible; opacity: 1; transform: translateY(0); }
#nav-components .back-box { display: inline-block; width: 3rem; height: 4px; border-radius: var(--border-radius-xlarge); background-color: var(--overlay-color-dark-3); }
#nav-components .mobile-close-btn { position: absolute; display: flex; right: 0; top: 0; width: 2rem; height: 2rem; background-color: var(--bg-color-body); border-radius: var(--border-radius-circle); align-items: center; justify-content: center; }
#nav-components .nav-menu > .nav-item { font-size: 1rem; color: var(--font-color-main); }
#nav-components .nav-menu .nav-a .iconfont { font-size: 1rem; }
#nav-components .nav-menu .nav-a .nav-icon { display: none; }
#nav-components .nav-menu .sub-menu { background-color: var(--bg-color-body); border-radius: var(--border-radius-medium); border-top-left-radius: 0; }
.nav-fixed { padding-top: var(--height-nav-fixed); }
@media (max-width: 767.98px) { .nav-fixed { padding-top: calc(var(--height-nav-fixed) - 1rem); } }
/*---------- 导航栏样式end ----------*/
/*---------- 文章分类样式st ----------*/
.category-box { position: relative; width: 100%; height: 12rem; max-height: 100%; overflow: hidden; }
.category-box .category-item { position: absolute; color: var(--bg-color-main); width: 100%; height: 100%; background-color: var(--overlay-color-dark-2); }
.category-box .category-item .category-info { width: 100%; height: 100%; }
.category-box .category-item .category-name { display: block; font-size: 1.15rem; font-weight: bold; }
.category-box .category-item .category-desc { display: block; font-size: 0.85rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
.category-box img { width: 100%; height: 100%; object-fit: cover; }
/*---------- 文章分类样式end ----------*/
/*---------- 文章列表样式st ----------*/
.post-list > div:nth-child(1) .post-item { animation-delay: 0.4s; }
.post-list > div:nth-child(2) .post-item { animation-delay: 0.4s; }
.post-list > div:nth-child(3) .post-item { animation-delay: 0.4s; }
.post-list > div:nth-child(4) .post-item { animation-delay: 0.6s; }
.post-list > div:nth-child(5) .post-item { animation-delay: 0.6s; }
.post-list > div:nth-child(6) .post-item { animation-delay: 0.6s; }
.post-list > div:nth-child(7) .post-item { animation-delay: 0.8s; }
.post-list > div:nth-child(8) .post-item { animation-delay: 0.8s; }
.post-list > div:nth-child(9) .post-item { animation-delay: 0.8s; }
@media (max-width: 767.98px) { .post-list > div:nth-child(1) .post-item { animation-delay: 0.4s; }
.post-list > div:nth-child(2) .post-item { animation-delay: 0.4s; }
.post-list > div:nth-child(3) .post-item { animation-delay: 0.6s; }
.post-list > div:nth-child(4) .post-item { animation-delay: 0.6s; }
.post-list > div:nth-child(5) .post-item { animation-delay: 0.8s; }
.post-list > div:nth-child(6) .post-item { animation-delay: 0.8s; }
.post-list > div:nth-child(7) .post-item { animation-delay: 1s; } }
.post-list .post-item { position: relative; min-width: 0; word-wrap: break-word; align-self: stretch; flex: 1 1 auto; overflow: hidden; border-radius: var(--border-radius-medium); border: var(--border-solid-main); box-shadow: var(--shadow-box-main); background: var(--gradient-0deg); background-clip: padding-box; opacity: 0; animation: fade-in-top 0.5s 0.3s forwards; -webkit-animation: fade-in-top 0.5s 0.3s forwards; }
.post-list .post-item:hover { background: var(--bg-color-main) !important; box-shadow: var(--shadow-box-hover); }
.post-list .post-item:hover .post-cover img { transform: scale(1.1); }
.post-list .post-item:hover .post-head > a { color: var(--color-blue-gray-medium) !important; }
.post-list .post-item .post-cover { position: relative; display: block; overflow: hidden; padding: 0; flex-shrink: 0; }
.post-list .post-item .post-cover::after { content: ""; display: block; padding-top: 60%; }
.post-list .post-item .post-cover img { width: 100%; height: 100%; transition: transform .3s ease-in-out; object-fit: cover; }
.post-list .post-item .post-cover a { position: absolute; top: 0; bottom: 0; left: 0; right: 0; border: 0; border-radius: inherit; background-size: cover; background-repeat: no-repeat; background-position: 50% 50%; background-clip: padding-box; }
.post-list .post-item .post-info { height: 100%; width: 100%; cursor: pointer; position: relative; overflow: hidden; gap: 0.5rem; }
.post-list .post-item .post-info .post-head > a { margin-bottom: 0.25rem; font-size: 1rem; font-weight: 600; line-height: 1.5; color: var(--font-color-main); transition: color .3s ease 0s; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
.post-list .post-item .post-info .post-meta-wrap { --font-color-main: var(--font-color-main-light); color: var(--font-color-main); }
.post-list .post-item .post-info .post-description { color: var(--font-color-main-transparent); font-size: 14px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
@media (max-width: 767.98px) { .post-list .post-item { box-shadow: var(--shadow-box-small); } }
/* -------------段落省略--------- */
.author-content .author-text { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
.post-meta-wrap .author-name, .post-meta-wrap .post-meta { color: var(--font-color-main); font-size: 0.85rem; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
@media (max-width: 767.98px) { .post-meta-wrap .author-name, .post-meta-wrap .post-meta { font-size: 0.8rem; } }
/*---------- 文章列表样式end ----------*/
/*---------- 文章列表->分页str ----------*/
.pagination { gap: 0.5rem; opacity: 0; animation: fade-in-top 0.5s 0.8s forwards; -webkit-animation: fade-in-top 0.5s 0.8s forwards; }
.pagination .page-item { width: 2rem; height: 2rem; }
.pagination .page-item .page-link { color: var(--font-color-main); background: var(--gradient-45deg); background-clip: padding-box; border: var(--border-solid-main); box-shadow: var(--shadow-box-small); }
.pagination .page-item.prev .iconfont, .pagination .page-item.next .iconfont { font-size: 0.9rem; }
.pagination .page-item.active .page-link, .pagination .page-item:hover .page-link { font-weight: bold; color: var(--color-primary-dark-1); background: var(--bg-color-main) !important; box-shadow: var(--shadow-box-main); }
/*---------- 文章列表分页end ----------*/
/*---------- 侧边栏样式st ----------*/
.hh-widget, .card { width: 100%; color: var(--font-color-main); border: var(--border-solid-main); border-radius: var(--border-radius-medium); box-shadow: var(--shadow-box-main); background: var(--gradient-45deg); background-clip: padding-box; }
.hh-widget:not(.no-animation), .card:not(.no-animation) { opacity: 0; animation: fade-in-top 0.5s 0.3s forwards; -webkit-animation: fade-in-top 0.5s 0.3s forwards; }
.main-sidebar .sidebar-sticky { top: 88px; z-index: 2 !important; transition: top 0.3s ease; }
.main-sidebar .sidebar-sticky.visible-top { top: 20px; }
.main-sidebar .widget-title { display: inline-block; font-size: 1rem; font-weight: 700; }
.main-sidebar .widget-title > .iconfont { font-size: 1.1rem; }
/*----------侧边栏样式end ----------*/
/*----------底部样式st ----------*/
.footer { color: var(--font-color-main); background-color: var(--bg-color-main); font-size: 14px; min-height: var(--height-footer); }
@media (max-width: 767.98px) { .footer .container { flex-direction: column; align-items: center; }
.footer .footer-left { text-align: center; justify-content: center; } }
.footer .theme-toggle { margin: 0 auto; gap: 0.15rem; background: var(--bg-color-body); border-radius: var(--border-radius-xlarge); border: var(--border-solid-small); }
.footer .theme-toggle button { line-height: 1; background: transparent; border-radius: var(--border-radius-large); }
.footer .theme-toggle button.active, .footer .theme-toggle button:hover { background: var(--bg-color-main); }
.footer .theme-toggle .iconfont { font-size: 0.85rem; color: var(--font-color-main-light); }
.footer .social-info-list a { display: flex; width: 1.75rem; height: 1.75rem; background-color: var(--bg-color-main-dark); border-radius: var(--border-radius-circle); align-items: center; justify-content: center; transition: background-color 0.2s; }
.footer .social-info-list a i { color: var(--bg-color-main); font-size: 1rem; }
.footer .social-info-list a:hover { background-color: var(--bg-color-body); }
.footer .social-info-list a:hover i { color: var(--font-color-main); }
main > .container { min-height: calc(100vh - 6rem - var(--height-footer)); }
/*---------- 底部样式end ----------*/
/*---------- 文章+页面-面包屑样式st ----------*/
.breadcrumb { font-size: 0.85rem; background: none !important; opacity: 0; animation: fade-in-top 0.3s 0.2s forwards; -webkit-animation: fade-in-top 0.3s 0.2s forwards; }
.breadcrumb li a, .breadcrumb li span { color: var(--font-color-main-light); font-size: 0.8rem; line-height: 1; padding: 0.2rem 0.5rem; background: linear-gradient(to right, var(--bg-color-primary), var(--overlay-color-light-2)); border-radius: var(--border-radius-xlarge); border: var(--border-solid-small); border-bottom-left-radius: var(--border-radius-small); box-shadow: var(--shadow-box-small); }
.breadcrumb li span { color: var(--font-color-main); box-shadow: var(--shadow-inset-box); }
.breadcrumb li:hover a { box-shadow: var(--shadow-inset-box); }
.breadcrumb > li + li:before { opacity: .6; padding: 0 0.35rem; color: var(--font-color-main-transparent); content: "\003e"; }
/*---------- 文章+页面-面包屑样式end ----------*/
/*---------- 文章内容样式end ----------*/
.post-header .author-left, .post-header .author-right { --font-color-main: var(--font-color-main-transparent); color: var(--font-color-main) !important; }
.post-head, .post-content { color: var(--font-color-main); }
.post .iconfont { font-size: 1rem; }
/* 文章内容样式 */
.post-content { position: relative; box-sizing: border-box; }
/* 文章版权样式 */
.post-copyright { position: relative; font-size: 0.9rem; line-height: 1.8; color: var(--font-color-main); border-radius: var(--border-radius-medium); box-shadow: var(--shadow-inset-box); z-index: 1; border: var(--border-solid-small); }
.copyright-svgname { position: absolute; height: 3rem; top: 30%; right: 0; opacity: 0.9; z-index: -1; }
/* 文章结束样式 */
.post-end { color: var(--border-color-main); }
.post-end::after, .post-end::before { content: ''; background: var(--border-color-main); max-width: 50%; height: 0.05rem; margin: 0 1rem; flex: 1; }
/* 文章标签样式 */
.category-and-tags { gap: 0.5rem; }
.category-and-tags a { font-size: 0.75rem; color: var(--font-color-main-transparent); padding: 0.25rem 0.5rem; border-radius: var(--border-radius-large); border: var(--border-solid-main); background-color: var(--bg-color-secondary); }
.category-and-tags a:hover { background: var(--border-color-main); }
.category-and-tags .post-tags { gap: 0.5rem; }
.category-and-tags .post-tags a { padding: 0.15rem 0.5rem 0.15rem 0.15rem; }
.category-and-tags .post-tags a::before { content: '#'; display: inline-flex; margin-right: 0.25rem; background-color: var(--bg-color-main); width: 20px; height: 20px; line-height: 20px; font-weight: 700; justify-content: center; border-radius: var(--border-radius-large); }
/* 分享+赞赏 */
.post-tools { gap: 1rem; }
.post-tools .post-tools-item { gap: 0.35rem; }
.post-tools .post-tools-item .post-tools-title { color: var(--font-color-main-transparent); font-size: 0.9rem; }
.post-tools button { width: 3rem; height: 3rem; background-image: var(--gradient-45deg); box-shadow: var(--shadow-box-small); border: var(--border-solid-main); border-radius: var(--border-radius-xlarge); }
.post-tools button .iconfont { font-size: 1.2rem; }
.post-tools button:hover { box-shadow: var(--shadow-inset-box); }
/* 下一篇、上一篇 */
.post-next-prev { gap: 1rem; line-height: 1.8; }
.post-next-prev .post-next, .post-next-prev .post-prev { position: relative; }
.post-next-prev .post-next .next-prev-title, .post-next-prev .post-prev .next-prev-title { cursor: default; line-height: 1; font-size: 1.25rem; }
.post-next-prev .post-next:hover .next-prev-title, .post-next-prev .post-prev:hover .next-prev-title { opacity: 0.7; }
.post-next-prev a { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
/*---------- 文章内容样式end ----------*/
/*---------- 评论样式st ----------*/
#comments { font-size: 0.9rem; }
/* 评论框 */
#comment-form .form-control { font-size: 0.9rem; }
#comment-form .comment-form-info input:focus { background-color: var(--overlay-color-light-5) !important; }
#comment-form .comment-form-info textarea:focus { background-color: var(--overlay-color-light-5) !important; }
.com-footer .com-tool-list .com-tool-item { position: relative; border-radius: var(--border-radius-base); }
.com-footer .com-tool-list .com-tool-item:hover, .com-footer .com-tool-list .com-tool-item.active { background: var(--bg-color-main); }
.com-footer .com-tool-list .iconfont { font-size: 1.25rem; }
.com-footer .com-tool-list .com-emoji { position: relative; }
.com-footer .com-tool-list .com-emoji .emoji-box { display: none; position: absolute; top: 3rem; left: -0.5rem; z-index: 10; background-image: var(--gradient-45deg); border: var(--border-solid-main); border-radius: var(--border-radius-base); overflow: hidden; box-shadow: var(--shadow-box-small); }
.com-footer .com-tool-list .com-emoji .emoji-dropdown { max-width: 100%; width: 22rem; height: 15rem; text-align: center; overflow-x: hidden; overflow-y: auto; margin: 0; }
.com-footer .com-tool-list .com-emoji .emoji-item { display: inline-block; font-size: 14px; cursor: pointer; }
.com-footer .com-tool-list .com-emoji .emoji-item .gif-img { min-width: 4rem; }
.com-footer .com-tool-list .com-emoji .emoji-item img { width: 2rem; height: auto; max-height: 100%; }
.com-footer .com-tool-list .com-emoji .emoji-item:hover { border-radius: var(--border-radius-medium); background-color: var(--bg-color-main); }
.com-footer .com-tool-list .com-emoji .emoji-bar { background-color: var(--bg-color-main); }
.com-footer .com-tool-list .com-emoji .emoji-bar li { cursor: pointer; }
.com-footer .com-tool-list .com-emoji .emoji-bar li:hover, .com-footer .com-tool-list .com-emoji .emoji-bar li.emoji-active { background-color: var(--bg-color-secondary); }
.com-footer .btn-card { color: var(--font-color-main); font-size: 0.85rem; background-image: var(--gradient-45deg); box-shadow: var(--shadow-box-main); border: var(--border-solid-small); border-radius: var(--border-radius-medium); background-clip: padding-box; }
.com-footer .btn-card:hover { box-shadow: var(--shadow-inset-box); }
/* 评论列表 */
.comment-body { position: relative; font-size: 0.85rem; gap: 0.5rem; }
.comment-body .comment-author { position: relative; gap: 0.5rem; }
.comment-body .comment-author .comment-name .comment-author-ua { font-size: 0.7rem; background-color: var(--color-primary); color: var(--bg-color-main); padding: 0.1rem 0.25rem; border-radius: var(--border-radius-small); }
.comment-body .comment-author .comment-time, .comment-body .comment-author .comment-ua { margin-right: 0.15rem; font-size: 0.8rem; color: var(--font-color-main-transparent); }
.comment-body .comment-author img { width: 40px; height: 40px; border-radius: var(--border-radius-circle); border: var(--border-solid-main); }
.comment-body .comment-content { word-break: break-all; }
.comment-body .comment-content p { display: inline-block; margin: 0; }
.comment-body .comment-content .emoji-image { display: inline-block !important; width: 2rem; height: auto; max-height: 100%; vertical-align: middle; }
.comment-body .comment-content img { display: block; max-width: 100%; width: auto; height: 10rem; margin: 0.5rem 0; border-radius: var(--border-radius-small); }
.comment-body .comment-content .repy-to-author a { color: var(--red); }
.comment-body .comment-footer { position: absolute; right: 0; bottom: 0; color: var(--font-color-main-transparent); font-size: 0.85rem; }
.comment-body .comment-footer .iconfont { color: var(--border-color-main); }
.comment-body .comment-footer:hover .iconfont { color: var(--font-color-main) !important; }
.comment-body:hover .comment-footer .iconfont { color: var(--font-color-main-transparent); }
.comment-parent { border-radius: var(--border-radius-medium); box-shadow: var(--shadow-inset-box); border: var(--border-solid-small); }
.comment-parent .comment-list { border-radius: var(--border-radius-medium); box-shadow: var(--shadow-inset-box); border: var(--border-solid-small); }
.comment-parent .comment-list .comment-list .comment-child { border-bottom: 1px dashed var(--overlay-color-dark-1); }
.comment-parent .comment-list .comment-list .comment-child:last-child { border: none; }
.comment-parent .comment-list .repy-to-author + p { display: contents; }
.comment-child, .comment-parent { margin-bottom: 0.25rem; }
.comment-child:last-child, .comment-parent:last-child { margin-bottom: 0 !important; }
/*评论下一页、上一页*/
.comment-pagination ol { gap: 0.5rem; }
.comment-pagination a { width: 2rem; height: 2rem; display: flex; background-image: var(--gradient-45deg); border: var(--border-solid-small); border-radius: var(--border-radius-medium); box-shadow: var(--shadow-box-main); background-clip: padding-box; justify-content: center; align-items: center; }
.comment-pagination li.current a { font-weight: 700; }
.comment-pagination a:hover, .comment-pagination li.current a { color: var(--color-primary); box-shadow: var(--shadow-inset-box); }
.comment-pagination .com-next .iconfont, .comment-pagination .com-prev .iconfont { font-size: 0.9rem; }
/*---------- 评论样式end ----------*/
/*---------- 弹窗工具:搜索+分享+赞赏按钮样式st ----------*/
.pop-tool-overlay-bg { opacity: 0; visibility: hidden; position: fixed; inset: 0; background: var(--overlay-color-light-1); -webkit-backdrop-filter: var(--backdrop-filter-main); backdrop-filter: var(--backdrop-filter-main); z-index: 997; -webkit-transition: all 0.4s ease-out; transition: all 0.4s ease-out; transform: rotate(45deg) scale(0); }
/* 应用Mixins */
.open .pop-tool-overlay-bg { opacity: 1 !important; visibility: visible !important; transform: rotate(0) scale(1) !important; }
.open .pop-tool-box { opacity: 1 !important; visibility: visible !important; top: 45% !important; transform: translate(-50%, -50%) scale(1) !important; }
.pop-tool-box { opacity: 0; visibility: hidden; position: fixed; width: calc(-20px + 100vw); max-height: calc(100vh - 6rem); max-width: 50rem; z-index: 998; top: 35%; left: 50%; transform: translate(-50%, -50%) scale(0); overflow: hidden; -webkit-transition: all 0.3s ease-out; transition: all 0.3s ease-out; }
/* 海报生成 */
.main-poster .poster-box { width: 400px; max-width: calc(100vw - 1rem); padding: 0 !important; overflow: unset; color: var(--font-color-main); }
.main-poster .poster-box .poster-post-box { --poster-text-color: var(--font-color-main-light); position: relative; background: var(--gradient-0deg); width: 100%; overflow: hidden; border-radius: var(--border-radius-base); }
.main-poster .poster-box .poster-cover { height: 200px; border-radius: var(--border-radius-small); overflow: hidden; }
.main-poster .poster-box .poster-content { gap: 1rem; }
.main-poster .poster-box .poster-content .poster-date { height: 100%; color: var(--gray-dark); background-color: var(--white); border-radius: var(--border-radius-medium); }
.main-poster .poster-box .poster-content .poster-post-content .poster-post-title { overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; white-space: normal; word-break: break-all; }
.main-poster .poster-box .poster-content .poster-post-content .poster-post-text { font-size: 0.9rem; color: var(--poster-text-color); }
.main-poster .poster-box .poster-footer { border: var(--border-solid-small); }
.main-poster .poster-box .down-btn-box { width: 100%; position: absolute; bottom: -4rem; }
/* 赞赏独立样式 */
.main-reward .reward-box { width: auto; }
.main-reward .reward-content { gap: 1rem; }
.main-reward .reward-content .reward-qr { color: var(--font-color-muted); box-shadow: var(--shadow-inset-box); border-radius: var(--border-radius-base); overflow: hidden; padding: 0.25rem; }
.main-reward .reward-content img { width: 10rem; border-radius: var(--border-radius-base); }
@media (max-width: 767.98px) { .main-reward .reward-content img { width: 8rem; } }
/* 分享独立样式 */
.share-box { top: 50%; }
.share-box p { text-align: center; color: var(--font-color-main-transparent); background-color: var(--bg-color-primary); border-radius: var(--border-radius-base); border: var(--border-solid-small); }
.share-box p:hover { color: var(--font-color-main); background: var(--overlay-color-light-5); }
.share-box .share-a { gap: 20px; }
.share-box .share-a .share-item { width: 3rem; height: 3rem; background-image: var(--gradient-0deg); box-shadow: var(--shadow-box-main); border: var(--border-solid-main); background-clip: padding-box; border-radius: var(--border-radius-circle); }
.share-box .share-a .share-item:hover { box-shadow: var(--shadow-inset-box); }
.share-box .wechat-qrcode img, .share-box .zdyqr-qrcode img { width: 10rem; height: 10rem; }
/* 搜索独立样式 */
.search-box .search-form { position: relative; }
.search-box .search-name h5 { font-weight: 700; }
.search-box .form-control { position: relative; width: 100%; height: 100%; padding: 0.6rem 2rem 0.6rem 1rem; font-size: 0.9rem; border-radius: var(--border-radius-medium); }
.search-box .site-search-btn { position: absolute; right: 0; top: 0; width: 3rem; height: 100%; z-index: 1; }
/* 关闭按钮样式 */
.close-btn { position: absolute; right: 0; top: 0; background: var(--font-color-main); border-bottom-left-radius: var(--border-radius-medium); }
.close-btn i { color: var(--bg-color-main); }
/*---------- 搜索+分享+赞赏按钮样式end ----------*/

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More