feat: rebuild xiteng.site homelab platform

This commit is contained in:
2026-08-12 09:48:25 +08:00
parent 557b0eca33
commit 5b84988789
128 changed files with 14979 additions and 292 deletions
+37 -15
View File
@@ -1,19 +1,31 @@
services:
hedgedoc-db:
image: postgres:16-alpine
image: postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777
environment:
- POSTGRES_USER=$POSTGRES_USER
- POSTGRES_PASSWORD=$POSTGRES_PASSWORD
- POSTGRES_DB=$POSTGRES_DB
container_name: hedgedoc_db
restart: unless-stopped
labels:
- "xiteng.site.component.hedgedoc-db.enabled=true"
- "xiteng.site.component.hedgedoc-db.name=HedgeDoc PostgreSQL"
- "xiteng.site.component.hedgedoc-db.description=保存笔记、修订记录、会话与权限元数据。"
- "xiteng.site.component.hedgedoc-db.section=infrastructure"
- "xiteng.site.component.hedgedoc-db.category=数据层"
- "xiteng.site.component.hedgedoc-db.access=internal"
- "xiteng.site.component.hedgedoc-db.access-label=仅容器网络"
- "xiteng.site.component.hedgedoc-db.icon=PG"
- "xiteng.site.component.hedgedoc-db.icon-url=https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/postgresql.svg"
- "xiteng.site.component.hedgedoc-db.accent=blue"
- "xiteng.site.component.hedgedoc-db.order=540"
volumes:
- ./data:/var/lib/postgresql/data
networks:
- homelab_net
hedgedoc:
image: quay.io/hedgedoc/hedgedoc:latest
image: quay.io/hedgedoc/hedgedoc:1.11.1
container_name: hedgedoc
restart: unless-stopped
environment:
@@ -40,6 +52,7 @@ services:
- CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR=email
volumes:
- ./uploads:/hedgedoc/public/uploads
- ./custom/index-body.ejs:/hedgedoc/public/views/index/body.ejs:ro
depends_on:
- hedgedoc-db
ports:
@@ -62,19 +75,28 @@ services:
# --- 新增:开启 TLS 并指定解析器 ---
- "traefik.http.routers.hedgedoc.tls=true"
- "traefik.http.routers.hedgedoc.tls.certresolver=cfresolver"
# --- 2. Homepage 自动发现设置 ---
- "homepage.group=我的服务" # 分组名称
- "homepage.name=HedgeDoc" # 显示名称
- "homepage.icon=si-hedgedoc" # 图标 (支持 si, mdi 等前缀)
- "homepage.href=https://notes.xiteng.site" # 点击跳转的链接
- "homepage.description=实时 Markdown 协作" # 副标题描述
# --- 3. AutoKuma 自动发现设置 ---
# 格式: kuma.<自定义ID>.<监控类型>.<属性>
- "kuma.hedgedoc.http.name=HedgeDoc" # 监控项名称
- "kuma.hedgedoc.http.url=http://hedgedoc:3000" # 内网直连
# (可选) 每 60 秒检查一次,重试 3 次
- "kuma.hedgedoc.http.interval=60"
- "kuma.hedgedoc.http.max_retries=3"
- "xiteng.site.cache.hedgedoc.enabled=true"
- "xiteng.site.cache.hedgedoc.routers=hedgedoc,hedgedoc-http"
- "xiteng.site.cache.hedgedoc.paths=/assets/,/static/"
- "xiteng.site.cache.hedgedoc.edge-ttl=604800"
- "xiteng.site.cache.hedgedoc.stale-while-revalidate=86400"
# --- Xiteng Site dynamic catalog ---
- "xiteng.site.component.hedgedoc.enabled=true"
- "xiteng.site.component.hedgedoc.name=HedgeDoc"
- "xiteng.site.component.hedgedoc.description=实时 Markdown 协作、分享与技术笔记。"
- "xiteng.site.component.hedgedoc.section=services"
- "xiteng.site.component.hedgedoc.category=开发与协作"
- "xiteng.site.component.hedgedoc.url=https://notes.xiteng.site"
- "xiteng.site.component.hedgedoc.access=mixed"
- "xiteng.site.component.hedgedoc.access-label=公开入口 · 内容按笔记授权"
- "xiteng.site.component.hedgedoc.icon=HD"
- "xiteng.site.component.hedgedoc.icon-url=https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/hedgedoc.svg"
- "xiteng.site.component.hedgedoc.accent=yellow"
- "xiteng.site.component.hedgedoc.order=110"
- "xiteng.site.component.hedgedoc.navigation=new-tab"
- "xiteng.site.component.hedgedoc.portal-link=native"
- "xiteng.site.component.hedgedoc.monitor.enabled=true"
- "xiteng.site.component.hedgedoc.monitor.url=http://hedgedoc:3000"
networks:
- homelab_net
+182
View File
@@ -0,0 +1,182 @@
<div class="site-wrapper">
<div class="site-wrapper-inner">
<div class="cover-container">
<div class="masthead clearfix">
<div class="inner">
<h3 class="masthead-brand"></h3>
<nav>
<ul class="nav masthead-nav">
<li><a href="https://xiteng.site/?focus=hedgedoc#services">← xiteng.site</a></li>
<li class="ui-home<% if(!signin) { %> active<% } %>"><a href="#"><%= __('Intro') %></a>
</li>
<li class="ui-history<% if(signin) { %> active<% } %>"><a href="#"><%= __('History') %></a>
</li>
<div class="ui-signin" style="float: right; margin-top: 8px;<% if(signin) { %> display: none;<% } %>">
<% if (allowAnonymous && !disableNoteCreation) { %>
<a type="button" href="<%- serverURL %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New guest note') %></a>
<% } %>
<% if (authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.saml || authProviders.oauth2 || authProviders.email) { %>
<button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button>
<% } %>
</div>
<div class="ui-signout" style="float: right; margin-top: 8px;<% if(!signin) { %> display: none;<% } %>">
<% if (!disableNoteCreation) { %>
<a type="button" href="<%- serverURL %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New note') %></a>
<% } %>
<span class="ui-profile dropdown pull-right">
<button id="profileLabel" class="btn btn-sm btn-link ui-profile-label" style="padding-right: 0;" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="ui-avatar" width="20" height="20"><span class="hidden-xs hidden-sm">&ensp;<span class="ui-name"></span></span>&ensp;<i class="fa fa-caret-down"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="profileLabel">
<li><a href="<%- serverURL %>/features"><i class="fa fa-dot-circle-o fa-fw"></i> <%= __('Features') %></a></li>
<li><a href="<%- serverURL %>/me/export"><i class="fa fa-cloud-download fa-fw"></i> <%= __('Export user data') %></a></li>
<li><a class="ui-delete-user" data-toggle="modal" data-target=".delete-user-modal"><i class="fa fa-trash fa-fw"></i> <%= __('Delete user') %></a></li>
<li><a href="<%- serverURL %>/logout"><i class="fa fa-sign-out fa-fw"></i> <%= __('Sign Out') %></a></li>
</ul>
</span>
</div>
</ul>
</nav>
</div>
</div>
<div id="home" class="section"<% if(signin) { %> style="display:none;"<% } %>>
<div class="inner cover">
<h1 class="cover-heading"><img src="<%- serverURL %>/banner/banner_vertical_color.svg" width="400" alt="HedgeDoc logo"></h1>
<p class="lead">
Ideas grow better together
</p>
<% if (infoMessage && infoMessage.length > 0) { %>
<div class="alert alert-info" style="max-width: 400px; margin: 0 auto;"><%= infoMessage %></div>
<% } %>
<% if (errorMessage && errorMessage.length > 0) { %>
<div class="alert alert-danger" style="max-width: 400px; margin: 0 auto;"><%= errorMessage %></div>
<% } %>
<% if (authProviders.facebook || authProviders.twitter || authProviders.github || authProviders.gitlab || authProviders.mattermost || authProviders.dropbox || authProviders.google || authProviders.ldap || authProviders.saml || authProviders.oauth2 || authProviders.email) { %>
<span class="ui-signin">
<br>
<a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a>
</span>
<span class="ui-or"><%= __('or') %></span>
<% } %>
<span class="ui-signin">
<a type="button" href="<%- serverURL %>/features" class="btn btn-lg btn-primary" style="min-width: 200px;"><%= __('Explore all features') %></a>
<br>
<br>
<img src="<%- serverURL %>/screenshot.png" class="screenshot ui-signin">
</span>
<div class="lead row" style="width: 90%; margin: 0 auto;">
<div class="col-md-4 inner">
<a href="<%- serverURL %>/features#Share-Notes">
<i class="fa fa-bolt fa-3x"></i>
<h4><%= __('Collaborate with URL') %></h4>
</a>
</div>
<div class="col-md-4 inner">
<a href="<%- serverURL %>/features#MathJax">
<i class="fa fa-bar-chart fa-3x"></i>
<h4><%= __('Support charts and MathJax') %></h4>
</a>
</div>
<div class="col-md-4 inner">
<a href="<%- serverURL %>/features#Slide-Mode">
<i class="fa fa-tv fa-3x"></i>
<h4><%= __('Support slide mode') %></h4>
</a>
</div>
</div>
</div>
</div>
<div id="history" class="section"<% if(!signin) { %> style="display:none;"<% } %>>
<div class="ui-signin"<% if(signin) { %> style="display:none;"<% } %>>
<p><%= __('Below is the history from browser') %></p>
</div>
<br>
<form class="form-inline">
<div class="form-group" style="vertical-align: bottom;">
<input class="form-control ui-use-tags" placeholder="<%= __('Select tags...') %>" />
</div>
<div class="form-group">
<input class="search form-control" placeholder="<%= __('Search keyword...') %>" />
</div>
<a href="#" class="sort btn btn-default" data-sort="text" title="<%= __('Sort by title') %>">
<%= __('Title') %>
</a>
<a href="#" class="sort btn btn-default" data-sort="timestamp" title="<%= __('Sort by time') %>">
<%= __('Time') %>
</a>
<span class="hidden-xs hidden-sm">
<a href="#" class="btn btn-default ui-save-history" title="<%= __('Export history') %>"><i class="fa fa-save"></i></a>
<span class="btn btn-default btn-file ui-open-history" title="<%= __('Import history') %>">
<i class="fa fa-folder-open-o"></i><input type="file" />
</span>
<a href="#" class="btn btn-default ui-clear-history" title="<%= __('Clear history') %>" data-toggle="modal" data-target=".delete-history-modal"><i class="fa fa-trash-o"></i></a>
</span>
<a href="#" class="btn btn-default ui-refresh-history" title="<%= __('Refresh history') %>"><i class="fa fa-refresh"></i></a>
</form>
<h4 class="ui-nohistory" style="display:none;">
<%= __('No history') %>
</h4>
<a href="#" class="btn btn-primary ui-import-from-browser" style="display:none;"><%= __('Import from browser') %></a>
<ul id="history-list" class="list">
</ul>
<ul class="pagination"></ul>
</div>
<div class="mastfoot">
<div class="inner">
<select class="ui-locale"></select>
<p>
<%- __('Powered by %s', '<a href="https://hedgedoc.org">HedgeDoc</a>') %> | <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></a> | <a href="<%- sourceURL %>" target="_blank" rel="noopener"><%= __('Source Code') %></a><% if(imprint) { %> | <a href="<%- serverURL %>/s/imprint" target="_blank" rel="noopener"><%= __('Imprint') %></a><% } %><% if(privacyStatement) { %> | <a href="<%- serverURL %>/s/privacy" target="_blank" rel="noopener"><%= __('Privacy') %></a><% } %><% if(termsOfUse) { %> | <a href="<%- serverURL %>/s/terms-of-use" target="_blank" rel="noopener"><%= __('Terms of Use') %></a><% } %>
</p>
<h6 class="social-foot">
<%- __('Follow us on %s and %s.', '<a href="https://github.com/hedgedoc/hedgedoc" target="_blank" rel="noopener"><i class="fa fa-github"></i> GitHub</a>, <a href="https://community.hedgedoc.org" target="_blank" rel="noopener"><i class="fa fa-users" aria-hidden="true"></i> Discourse</a>, <a href="https://chat.hedgedoc.org" target="_blank" rel="noopener"><i class="fa fa-comments"></i> Matrix</a>, <a href="https://social.hedgedoc.org/mastodon" target="_blank" rel="noopener"><i class="fa fa-mastodon"></i> Mastodon</a>', '<a href="https://translate.hedgedoc.org" target="_blank" rel="noopener"><i class="fa fa-globe"></i> POEditor</a>') %>
</h6>
</div>
</div>
</div>
</div>
</div>
<!-- delete history modal -->
<div class="modal fade delete-history-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="myModalLabel"><%= __('Are you sure?') %></h4>
</div>
<div class="modal-body">
<h5 class="ui-delete-history-modal-msg"></h5>
<strong class="ui-delete-history-modal-item"></strong>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%= __('Cancel') %></button>
<button type="button" class="btn btn-danger ui-delete-history-modal-confirm"><%= __('Yes, do it!') %></button>
</div>
</div>
</div>
</div>
<!-- delete user modal -->
<div class="modal fade delete-user-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="myModalLabel"><%= __('Are you sure?') %></h4>
</div>
<div class="modal-body">
<h5 class="ui-delete-user-modal-msg"><%= __('Do you really want to delete your user account?') %></h5>
<strong class="ui-delete-user-modal-item"><%= __('This will delete your account, all notes that are owned by you and remove all references to your account from other notes.') %></strong>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default ui-delete-user-modal-cancel" data-dismiss="modal"><%= __('Cancel') %></button>
<a type="button" class="btn btn-danger" href="<%- serverURL %>/me/delete/<%- deleteToken %>"><%= __('Yes, do it!') %></a>
</div>
</div>
</div>
</div>
<%- include('../shared/signin-modal') %>