Quellcode durchsuchen

Feat add index page (#1)

添加响应式的首页前端,并且优化index page
Signed-off-by: longjin <longjin@DragonOS.org>
LoGin vor 1 Woche
Ursprung
Commit
127b8cb813

+ 16 - 0
src/main.rs

@@ -207,6 +207,16 @@ async fn named_file_to_response(
     Ok(response)
 }
 
+#[get("/")]
+async fn index() -> Result<NamedFile, actix_web::Error> {
+    NamedFile::open_async("templates/index.html")
+        .await
+        .map_err(|e| {
+            log::error!("无法加载首页: {}", e);
+            actix_web::error::ErrorInternalServerError("无法加载首页")
+        })
+}
+
 #[actix_web::main]
 async fn main() -> std::io::Result<()> {
     let config = config::load_config("config.toml")
@@ -221,6 +231,12 @@ async fn main() -> std::io::Result<()> {
     builder.init();
     HttpServer::new(|| {
         App::new()
+            .service(
+                actix_files::Files::new("/assets", "templates/assets")
+                    .show_files_listing()
+                    .use_last_modified(true),
+            )
+            .service(index)
             .service(autoindex)
             .default_service(web::route().to(|| async {
                 HttpError::not_found("页面不存在", "您访问的页面不存在,请检查URL是否正确")

+ 668 - 0
templates/assets/css/main.css

@@ -0,0 +1,668 @@
+/* DragonOS镜像站首页样式 */
+#wrapper {
+  margin: 0 5%;
+  padding: 0 1rem;
+  overflow-x: hidden;
+  position: relative;
+  width: 90%;
+  max-width: 90%;
+}
+
+:root {
+  --dragon-light-blue: #4da6ff; /* 亮蓝 */
+  --dragon-dark-blue: #1a56db; /* 深蓝 */
+  --dragon-purple: #db34d3; /* 粉紫 */
+  --dragon-dark: #111827;
+  --dragon-light: #f3f4f6;
+}
+
+body {
+  background: linear-gradient(135deg, var(--dragon-light) 0%, #e5e7eb 100%);
+  font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
+  margin: 0;
+  padding: 2rem;
+  color: var(--dragon-dark);
+  min-height: 100vh;
+}
+
+/* 保持原有加载动画 */
+.is-preload {
+  opacity: 0;
+  transition: opacity 0.5s ease-in-out;
+}
+
+.is-preload.is-loaded {
+  opacity: 1;
+}
+
+/* 添加页面滚动时的固定导航栏 */
+#nav {
+  position: relative;
+  top: 0;
+  width: 100%;
+  z-index: 1000;
+  background-color: #fff;
+  padding: 1rem;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 为导航栏链接添加更多悬停效果 */
+#nav ul li a:hover {
+  background-color: #e0e0e0;
+  border-radius: 4px;
+  color: #333;
+  text-decoration: underline;
+}
+
+#header {
+  background: linear-gradient(
+      135deg,
+      rgba(255, 255, 255, 0.9) 0%,
+      rgba(255, 255, 255, 0.7) 100%
+    ),
+    url("https://dragonos.org/wp-content/uploads/2023/03/图形中英文完整@0.5x-1024x275.png")
+      no-repeat center center/cover;
+  padding: 6rem 0;
+  text-align: center;
+  animation: fadeIn 1s ease-in-out;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+  position: relative;
+  z-index: 1;
+}
+
+#header::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(255, 255, 255, 0.7);
+  z-index: -1;
+}
+
+/* 定义淡入动画 */
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+
+#header h1 {
+  font-size: 3rem;
+  color: var(--dragon-dark-blue);
+  margin: 0;
+  font-weight: 700;
+  animation: slideInDown 0.8s ease-out;
+  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  letter-spacing: -0.5px;
+  line-height: 1.2;
+}
+
+/* 定义下滑动画 */
+@keyframes slideInDown {
+  from {
+    transform: translateY(-20px);
+    opacity: 0;
+  }
+  to {
+    transform: translateY(0);
+    opacity: 1;
+  }
+}
+
+#header p {
+  font-size: 1.5rem;
+  color: #6b7280;
+  margin: 1rem 0 0;
+  animation: fadeInUp 1s ease-out;
+  font-weight: 500;
+  max-width: 800px;
+  margin-left: auto;
+  margin-right: auto;
+  line-height: 1.5;
+}
+
+/* 定义淡入上滑动画 */
+@keyframes fadeInUp {
+  from {
+    transform: translateY(20px);
+    opacity: 0;
+  }
+  to {
+    transform: translateY(0);
+    opacity: 1;
+  }
+}
+
+#nav {
+  background: rgba(255, 255, 255, 0.95);
+  padding: 0.8rem 0;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+  backdrop-filter: blur(10px);
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+#nav ul {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  gap: 0.5rem;
+  width: 100%;
+}
+
+#nav ul li {
+  flex-grow: 0;
+  flex-shrink: 0;
+}
+
+#nav ul li {
+  position: relative;
+}
+
+#nav ul li a {
+  text-decoration: none;
+  color: var(--dragon-dark-blue);
+  font-weight: 600;
+  padding: 0.5rem 1rem;
+  transition: all 0.3s ease;
+  position: relative;
+}
+
+#nav ul li a::after {
+  content: "";
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 0;
+  height: 2px;
+  background: linear-gradient(
+    90deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+  transition: width 0.3s ease;
+}
+
+#nav ul li a:hover {
+  color: var(--dragon-purple);
+  background-color: transparent;
+}
+
+#nav ul li a:hover::after {
+  width: 100%;
+}
+
+#nav ul li a.active {
+  color: var(--dragon-purple);
+}
+
+#nav ul li a.active::after {
+  width: 100%;
+}
+
+.main {
+  padding: 2rem;
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  margin-bottom: 2rem;
+}
+
+.spotlight {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 2rem 0;
+}
+
+.spotlight .content {
+  max-width: 600px;
+  text-align: center;
+}
+
+.spotlight .content h2 {
+  font-size: 2rem;
+  color: #333;
+  margin: 0 0 1rem;
+  font-weight: bold;
+}
+
+.spotlight .content h3 {
+  font-size: 1.2rem;
+  color: #666;
+  margin: 0 0 1.5rem;
+}
+
+.spotlight .content .actions {
+  display: flex;
+  justify-content: center;
+}
+
+.spotlight .content .actions .button {
+  background: linear-gradient(
+    45deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+  color: #fff;
+  padding: 0.75rem 1.5rem;
+  border: none;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 4px 6px rgba(26, 86, 219, 0.3);
+  font-weight: 600;
+  position: relative;
+  overflow: hidden;
+}
+
+.spotlight .content .actions .button:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 12px rgba(26, 86, 219, 0.4);
+  background: linear-gradient(45deg, #1a4fd8, #db34d3);
+}
+
+.spotlight .content .actions .button:active {
+  transform: translateY(0);
+}
+
+.spotlight .content .actions .button::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: linear-gradient(
+    45deg,
+    transparent,
+    rgba(255, 255, 255, 0.3),
+    transparent
+  );
+  transform: translateX(-100%);
+  transition: transform 0.6s ease;
+}
+
+.spotlight .content .actions .button:hover::after {
+  transform: translateX(100%);
+}
+
+.main.special {
+  background-color: #fff;
+  padding: 2rem;
+  margin: 2rem 0;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+  border-radius: 12px;
+  backdrop-filter: blur(10px);
+  animation: fadeIn 1s ease-in-out;
+  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+  border: 1px solid rgba(255, 255, 255, 0.3);
+}
+
+.main.special:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
+  border-color: rgba(255, 255, 255, 0.5);
+}
+
+.main.special h2 {
+  font-size: 1.8rem;
+  color: #333;
+  margin: 0 0 1rem;
+}
+
+.main.special ul.features {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 2rem;
+}
+
+.main.special ul.features li {
+  flex: 1 1;
+  text-align: center;
+}
+
+.main.special ul.features li a {
+  display: inline-block;
+  margin-bottom: 1rem;
+}
+
+.main.special ul.features li h3 {
+  font-size: 1.2rem;
+  color: #333;
+  margin: 0 0 0.5rem;
+}
+
+.main.special ul.features li a {
+  text-decoration: none;
+  color: #333;
+}
+
+.main.special ul.features li a:hover {
+  color: #555;
+  text-decoration: underline;
+}
+
+.main.special ul.actions {
+  padding-inline-start: 0;
+}
+
+#cta {
+  background: rgba(255, 255, 255, 0.95);
+  padding: 3rem 2rem;
+  margin: 3rem 0;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+  border-radius: 12px;
+  border: 1px solid rgba(79, 70, 229, 0.15);
+  animation: fadeIn 1s ease-in-out;
+  text-align: center;
+  backdrop-filter: blur(10px);
+  position: relative;
+  overflow: hidden;
+}
+
+#cta::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 4px;
+  background: linear-gradient(
+    90deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+}
+
+#cta h2 {
+  font-size: 2rem;
+  color: var(--dragon-dark-blue);
+  margin: 0 0 1.5rem;
+  font-weight: 600;
+}
+
+#cta ul {
+  list-style: none;
+  margin: 0 auto 2rem;
+  padding: 0;
+  display: flex;
+  flex-direction: column;
+  gap: 0.8rem;
+  max-width: 600px;
+}
+
+#cta ul li {
+  font-size: 1.2rem;
+  color: #555;
+  line-height: 1.6;
+}
+
+#cta .actions .button {
+  background: linear-gradient(
+    45deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+  color: #fff;
+  padding: 1rem 2rem;
+  border: none;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 4px 6px rgba(26, 86, 219, 0.3);
+  font-weight: 600;
+  font-size: 1.1rem;
+}
+
+#cta .actions .button:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 12px rgba(26, 86, 219, 0.4);
+  background: linear-gradient(45deg, #1a4fd8, #db34d3);
+}
+
+footer {
+  background: rgba(255, 255, 255, 0.9);
+  padding: 2rem 1.5rem;
+  text-align: center;
+  margin-top: 3rem;
+  box-shadow: 0 -4px 6px rgba(0, 0, 0, 0.05);
+  border-top: 1px solid rgba(0, 0, 0, 0.05);
+  backdrop-filter: blur(10px);
+}
+
+footer .copyright {
+  display: flex;
+  flex-direction: column;
+  gap: 0.5rem;
+  font-size: 0.9rem;
+  color: #555;
+  margin: 0;
+  line-height: 1.6;
+}
+
+footer .copyright a {
+  color: var(--dragon-dark-blue);
+  text-decoration: none;
+  transition: color 0.2s ease;
+}
+
+footer .copyright a:hover {
+  color: var(--dragon-purple);
+  text-decoration: underline;
+}
+
+footer::before {
+  content: "";
+  display: block;
+  width: 100px;
+  height: 2px;
+  background: linear-gradient(
+    90deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+  margin: 0 auto 1.5rem;
+  border-radius: 2px;
+}
+
+/* 立即加入我们按钮样式 - 与前往赞助按钮一致 */
+.cta-button {
+  background: linear-gradient(
+    45deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+  color: #fff;
+  padding: 1rem 2rem;
+  border: none;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 4px 6px rgba(26, 86, 219, 0.3);
+  font-weight: 600;
+  font-size: 1.1rem;
+}
+
+.cta-button:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 12px rgba(26, 86, 219, 0.4);
+  background: linear-gradient(45deg, #1a4fd8, #db34d3);
+}
+
+/* 立即加入我们按钮特殊样式 */
+.button.join-button {
+  background: linear-gradient(
+    45deg,
+    var(--dragon-purple),
+    var(--dragon-dark-blue)
+  );
+  font-size: 1.1rem;
+  padding: 0.8rem 2rem;
+  border-radius: 8px;
+  box-shadow: 0 4px 8px rgba(219, 52, 211, 0.3);
+  font-weight: 500;
+  text-transform: none;
+  letter-spacing: normal;
+}
+
+.button.join-button:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 12px rgba(219, 52, 211, 0.4);
+  background: linear-gradient(45deg, #e82ee8, #1a56db);
+}
+
+.button.join-button:active {
+  transform: translateY(0);
+}
+
+/* 移除按钮文字下划线 */
+.button,
+.cta-button {
+  text-decoration: none !important;
+}
+
+/* 资源中心卡片样式 */
+#first .content {
+  margin: 2rem 0;
+}
+
+.download-info {
+  display: flex;
+  justify-content: center;
+  gap: 3rem;
+  margin: 2rem 0;
+}
+
+.download-item {
+  background: rgba(255, 255, 255, 0.98);
+  padding: 2.5rem 2rem;
+  border-radius: 16px;
+  box-shadow: 0 8px 16px rgba(26, 86, 219, 0.08);
+  width: 320px;
+  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+  border: 1px solid rgba(77, 166, 255, 0.3);
+  position: relative;
+  overflow: hidden;
+  text-align: center;
+}
+
+.download-item::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 6px;
+  background: linear-gradient(
+    90deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+}
+
+.download-item:hover {
+  transform: translateY(-8px);
+  box-shadow: 0 12px 24px rgba(26, 86, 219, 0.15);
+  border-color: rgba(77, 166, 255, 0.6);
+}
+
+.download-item .icon {
+  font-size: 3rem;
+  color: var(--dragon-dark-blue);
+  margin-bottom: 1.5rem;
+  display: inline-block;
+  transition: all 0.3s ease;
+}
+
+.download-item:hover .icon {
+  transform: scale(1.1);
+  color: var(--dragon-purple);
+}
+
+.download-item h3 {
+  color: var(--dragon-dark-blue);
+  margin-bottom: 1.2rem;
+  font-size: 1.5rem;
+  font-weight: 700;
+  position: relative;
+}
+
+.download-item p {
+  color: var(--dragon-dark);
+  line-height: 1.6;
+}
+
+.download-item a {
+  display: inline-block;
+  color: var(--dragon-dark-blue);
+  text-decoration: none;
+  font-weight: 600;
+  padding: 0.5rem 1rem;
+  border-radius: 4px;
+  background: rgba(77, 166, 255, 0.1);
+  transition: all 0.3s ease;
+}
+
+.download-item a:hover {
+  color: white;
+  background: linear-gradient(
+    45deg,
+    var(--dragon-dark-blue),
+    var(--dragon-purple)
+  );
+  text-decoration: none;
+  transform: translateY(-2px);
+  box-shadow: 0 4px 8px rgba(26, 86, 219, 0.2);
+}
+
+/* 文件列表表格样式 */
+.file-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin: 2rem 0;
+  background: white;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+}
+
+.file-table th {
+  background: linear-gradient(
+    45deg,
+    color-mix(in srgb, var(--dragon-dark-blue) 80%, transparent),
+    color-mix(in srgb, var(--dragon-purple) 80%, transparent)
+  );
+  color: rgb(255, 255, 255);
+  padding: 1rem;
+  text-align: left;
+}
+
+.file-table td {
+  padding: 0.8rem 1rem;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.file-table tr:last-child td {
+  border-bottom: none;
+}
+
+.file-table a {
+  color: var(--dragon-dark-blue);
+  transition: color 0.2s ease;
+}
+
+.file-table a:hover {
+  color: var(--dragon-purple);
+  text-decoration: none;
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
templates/assets/js/breakpoints.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
templates/assets/js/browser.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
templates/assets/js/jquery.min.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 0
templates/assets/js/jquery.scrollex.min.js


+ 2 - 0
templates/assets/js/jquery.scrolly.min.js

@@ -0,0 +1,2 @@
+/* jquery.scrolly v1.0.0-dev | (c) @ajlkn | MIT licensed */
+(function(e){function u(s,o){var u,a,f;if((u=e(s))[t]==0)return n;a=u[i]()[r];switch(o.anchor){case"middle":f=a-(e(window).height()-u.outerHeight())/2;break;default:case r:f=Math.max(a,0)}return typeof o[i]=="function"?f-=o[i]():f-=o[i],f}var t="length",n=null,r="top",i="offset",s="click.scrolly",o=e(window);e.fn.scrolly=function(i){var o,a,f,l,c=e(this);if(this[t]==0)return c;if(this[t]>1){for(o=0;o<this[t];o++)e(this[o]).scrolly(i);return c}l=n,f=c.attr("href");if(f.charAt(0)!="#"||f[t]<2)return c;a=jQuery.extend({anchor:r,easing:"swing",offset:0,parent:e("body,html"),pollOnce:!1,speed:1e3},i),a.pollOnce&&(l=u(f,a)),c.off(s).on(s,function(e){var t=l!==n?l:u(f,a);t!==n&&(e.preventDefault(),a.parent.stop().animate({scrollTop:t},a.speed,a.easing))})}})(jQuery);

+ 123 - 0
templates/assets/js/main.js

@@ -0,0 +1,123 @@
+/*
+	Stellar by HTML5 UP
+	html5up.net | @ajlkn
+	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
+*/
+
+(function($) {
+
+	var	$window = $(window),
+		$body = $('body'),
+		$main = $('#main');
+
+	// Breakpoints.
+		breakpoints({
+			xlarge:   [ '1281px',  '1680px' ],
+			large:    [ '981px',   '1280px' ],
+			medium:   [ '737px',   '980px'  ],
+			small:    [ '481px',   '736px'  ],
+			xsmall:   [ '361px',   '480px'  ],
+			xxsmall:  [ null,      '360px'  ]
+		});
+
+	// Play initial animations on page load.
+		$window.on('load', function() {
+			window.setTimeout(function() {
+				$body.removeClass('is-preload');
+			}, 100);
+		});
+
+	// Nav.
+		var $nav = $('#nav');
+
+		if ($nav.length > 0) {
+
+			// Shrink effect.
+				$main
+					.scrollex({
+						mode: 'top',
+						enter: function() {
+							$nav.addClass('alt');
+						},
+						leave: function() {
+							$nav.removeClass('alt');
+						},
+					});
+
+			// Links.
+				var $nav_a = $nav.find('a');
+
+				$nav_a
+					.scrolly({
+						speed: 1000,
+						offset: function() { return $nav.height(); }
+					})
+					.on('click', function() {
+
+						var $this = $(this);
+
+						// External link? Bail.
+							if ($this.attr('href').charAt(0) != '#')
+								return;
+
+						// Deactivate all links.
+							$nav_a
+								.removeClass('active')
+								.removeClass('active-locked');
+
+						// Activate link *and* lock it (so Scrollex doesn't try to activate other links as we're scrolling to this one's section).
+							$this
+								.addClass('active')
+								.addClass('active-locked');
+
+					})
+					.each(function() {
+
+						var	$this = $(this),
+							id = $this.attr('href'),
+							$section = $(id);
+
+						// No section for this link? Bail.
+							if ($section.length < 1)
+								return;
+
+						// Scrollex.
+							$section.scrollex({
+								mode: 'middle',
+								initialize: function() {
+
+									// Deactivate section.
+										if (browser.canUse('transition'))
+											$section.addClass('inactive');
+
+								},
+								enter: function() {
+
+									// Activate section.
+										$section.removeClass('inactive');
+
+									// No locked links? Deactivate all links and activate this section's one.
+										if ($nav_a.filter('.active-locked').length == 0) {
+
+											$nav_a.removeClass('active');
+											$this.addClass('active');
+
+										}
+
+									// Otherwise, if this section's link is the one that's locked, unlock it.
+										else if ($this.hasClass('active-locked'))
+											$this.removeClass('active-locked');
+
+								}
+							});
+
+					});
+
+		}
+
+	// Scrolly.
+		$('.scrolly').scrolly({
+			speed: 1000
+		});
+
+})(jQuery);

+ 587 - 0
templates/assets/js/util.js

@@ -0,0 +1,587 @@
+(function($) {
+
+	/**
+	 * Generate an indented list of links from a nav. Meant for use with panel().
+	 * @return {jQuery} jQuery object.
+	 */
+	$.fn.navList = function() {
+
+		var	$this = $(this);
+			$a = $this.find('a'),
+			b = [];
+
+		$a.each(function() {
+
+			var	$this = $(this),
+				indent = Math.max(0, $this.parents('li').length - 1),
+				href = $this.attr('href'),
+				target = $this.attr('target');
+
+			b.push(
+				'<a ' +
+					'class="link depth-' + indent + '"' +
+					( (typeof target !== 'undefined' && target != '') ? ' target="' + target + '"' : '') +
+					( (typeof href !== 'undefined' && href != '') ? ' href="' + href + '"' : '') +
+				'>' +
+					'<span class="indent-' + indent + '"></span>' +
+					$this.text() +
+				'</a>'
+			);
+
+		});
+
+		return b.join('');
+
+	};
+
+	/**
+	 * Panel-ify an element.
+	 * @param {object} userConfig User config.
+	 * @return {jQuery} jQuery object.
+	 */
+	$.fn.panel = function(userConfig) {
+
+		// No elements?
+			if (this.length == 0)
+				return $this;
+
+		// Multiple elements?
+			if (this.length > 1) {
+
+				for (var i=0; i < this.length; i++)
+					$(this[i]).panel(userConfig);
+
+				return $this;
+
+			}
+
+		// Vars.
+			var	$this = $(this),
+				$body = $('body'),
+				$window = $(window),
+				id = $this.attr('id'),
+				config;
+
+		// Config.
+			config = $.extend({
+
+				// Delay.
+					delay: 0,
+
+				// Hide panel on link click.
+					hideOnClick: false,
+
+				// Hide panel on escape keypress.
+					hideOnEscape: false,
+
+				// Hide panel on swipe.
+					hideOnSwipe: false,
+
+				// Reset scroll position on hide.
+					resetScroll: false,
+
+				// Reset forms on hide.
+					resetForms: false,
+
+				// Side of viewport the panel will appear.
+					side: null,
+
+				// Target element for "class".
+					target: $this,
+
+				// Class to toggle.
+					visibleClass: 'visible'
+
+			}, userConfig);
+
+			// Expand "target" if it's not a jQuery object already.
+				if (typeof config.target != 'jQuery')
+					config.target = $(config.target);
+
+		// Panel.
+
+			// Methods.
+				$this._hide = function(event) {
+
+					// Already hidden? Bail.
+						if (!config.target.hasClass(config.visibleClass))
+							return;
+
+					// If an event was provided, cancel it.
+						if (event) {
+
+							event.preventDefault();
+							event.stopPropagation();
+
+						}
+
+					// Hide.
+						config.target.removeClass(config.visibleClass);
+
+					// Post-hide stuff.
+						window.setTimeout(function() {
+
+							// Reset scroll position.
+								if (config.resetScroll)
+									$this.scrollTop(0);
+
+							// Reset forms.
+								if (config.resetForms)
+									$this.find('form').each(function() {
+										this.reset();
+									});
+
+						}, config.delay);
+
+				};
+
+			// Vendor fixes.
+				$this
+					.css('-ms-overflow-style', '-ms-autohiding-scrollbar')
+					.css('-webkit-overflow-scrolling', 'touch');
+
+			// Hide on click.
+				if (config.hideOnClick) {
+
+					$this.find('a')
+						.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
+
+					$this
+						.on('click', 'a', function(event) {
+
+							var $a = $(this),
+								href = $a.attr('href'),
+								target = $a.attr('target');
+
+							if (!href || href == '#' || href == '' || href == '#' + id)
+								return;
+
+							// Cancel original event.
+								event.preventDefault();
+								event.stopPropagation();
+
+							// Hide panel.
+								$this._hide();
+
+							// Redirect to href.
+								window.setTimeout(function() {
+
+									if (target == '_blank')
+										window.open(href);
+									else
+										window.location.href = href;
+
+								}, config.delay + 10);
+
+						});
+
+				}
+
+			// Event: Touch stuff.
+				$this.on('touchstart', function(event) {
+
+					$this.touchPosX = event.originalEvent.touches[0].pageX;
+					$this.touchPosY = event.originalEvent.touches[0].pageY;
+
+				})
+
+				$this.on('touchmove', function(event) {
+
+					if ($this.touchPosX === null
+					||	$this.touchPosY === null)
+						return;
+
+					var	diffX = $this.touchPosX - event.originalEvent.touches[0].pageX,
+						diffY = $this.touchPosY - event.originalEvent.touches[0].pageY,
+						th = $this.outerHeight(),
+						ts = ($this.get(0).scrollHeight - $this.scrollTop());
+
+					// Hide on swipe?
+						if (config.hideOnSwipe) {
+
+							var result = false,
+								boundary = 20,
+								delta = 50;
+
+							switch (config.side) {
+
+								case 'left':
+									result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta);
+									break;
+
+								case 'right':
+									result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta));
+									break;
+
+								case 'top':
+									result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta);
+									break;
+
+								case 'bottom':
+									result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta));
+									break;
+
+								default:
+									break;
+
+							}
+
+							if (result) {
+
+								$this.touchPosX = null;
+								$this.touchPosY = null;
+								$this._hide();
+
+								return false;
+
+							}
+
+						}
+
+					// Prevent vertical scrolling past the top or bottom.
+						if (($this.scrollTop() < 0 && diffY < 0)
+						|| (ts > (th - 2) && ts < (th + 2) && diffY > 0)) {
+
+							event.preventDefault();
+							event.stopPropagation();
+
+						}
+
+				});
+
+			// Event: Prevent certain events inside the panel from bubbling.
+				$this.on('click touchend touchstart touchmove', function(event) {
+					event.stopPropagation();
+				});
+
+			// Event: Hide panel if a child anchor tag pointing to its ID is clicked.
+				$this.on('click', 'a[href="#' + id + '"]', function(event) {
+
+					event.preventDefault();
+					event.stopPropagation();
+
+					config.target.removeClass(config.visibleClass);
+
+				});
+
+		// Body.
+
+			// Event: Hide panel on body click/tap.
+				$body.on('click touchend', function(event) {
+					$this._hide(event);
+				});
+
+			// Event: Toggle.
+				$body.on('click', 'a[href="#' + id + '"]', function(event) {
+
+					event.preventDefault();
+					event.stopPropagation();
+
+					config.target.toggleClass(config.visibleClass);
+
+				});
+
+		// Window.
+
+			// Event: Hide on ESC.
+				if (config.hideOnEscape)
+					$window.on('keydown', function(event) {
+
+						if (event.keyCode == 27)
+							$this._hide(event);
+
+					});
+
+		return $this;
+
+	};
+
+	/**
+	 * Apply "placeholder" attribute polyfill to one or more forms.
+	 * @return {jQuery} jQuery object.
+	 */
+	$.fn.placeholder = function() {
+
+		// Browser natively supports placeholders? Bail.
+			if (typeof (document.createElement('input')).placeholder != 'undefined')
+				return $(this);
+
+		// No elements?
+			if (this.length == 0)
+				return $this;
+
+		// Multiple elements?
+			if (this.length > 1) {
+
+				for (var i=0; i < this.length; i++)
+					$(this[i]).placeholder();
+
+				return $this;
+
+			}
+
+		// Vars.
+			var $this = $(this);
+
+		// Text, TextArea.
+			$this.find('input[type=text],textarea')
+				.each(function() {
+
+					var i = $(this);
+
+					if (i.val() == ''
+					||  i.val() == i.attr('placeholder'))
+						i
+							.addClass('polyfill-placeholder')
+							.val(i.attr('placeholder'));
+
+				})
+				.on('blur', function() {
+
+					var i = $(this);
+
+					if (i.attr('name').match(/-polyfill-field$/))
+						return;
+
+					if (i.val() == '')
+						i
+							.addClass('polyfill-placeholder')
+							.val(i.attr('placeholder'));
+
+				})
+				.on('focus', function() {
+
+					var i = $(this);
+
+					if (i.attr('name').match(/-polyfill-field$/))
+						return;
+
+					if (i.val() == i.attr('placeholder'))
+						i
+							.removeClass('polyfill-placeholder')
+							.val('');
+
+				});
+
+		// Password.
+			$this.find('input[type=password]')
+				.each(function() {
+
+					var i = $(this);
+					var x = $(
+								$('<div>')
+									.append(i.clone())
+									.remove()
+									.html()
+									.replace(/type="password"/i, 'type="text"')
+									.replace(/type=password/i, 'type=text')
+					);
+
+					if (i.attr('id') != '')
+						x.attr('id', i.attr('id') + '-polyfill-field');
+
+					if (i.attr('name') != '')
+						x.attr('name', i.attr('name') + '-polyfill-field');
+
+					x.addClass('polyfill-placeholder')
+						.val(x.attr('placeholder')).insertAfter(i);
+
+					if (i.val() == '')
+						i.hide();
+					else
+						x.hide();
+
+					i
+						.on('blur', function(event) {
+
+							event.preventDefault();
+
+							var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
+
+							if (i.val() == '') {
+
+								i.hide();
+								x.show();
+
+							}
+
+						});
+
+					x
+						.on('focus', function(event) {
+
+							event.preventDefault();
+
+							var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']');
+
+							x.hide();
+
+							i
+								.show()
+								.focus();
+
+						})
+						.on('keypress', function(event) {
+
+							event.preventDefault();
+							x.val('');
+
+						});
+
+				});
+
+		// Events.
+			$this
+				.on('submit', function() {
+
+					$this.find('input[type=text],input[type=password],textarea')
+						.each(function(event) {
+
+							var i = $(this);
+
+							if (i.attr('name').match(/-polyfill-field$/))
+								i.attr('name', '');
+
+							if (i.val() == i.attr('placeholder')) {
+
+								i.removeClass('polyfill-placeholder');
+								i.val('');
+
+							}
+
+						});
+
+				})
+				.on('reset', function(event) {
+
+					event.preventDefault();
+
+					$this.find('select')
+						.val($('option:first').val());
+
+					$this.find('input,textarea')
+						.each(function() {
+
+							var i = $(this),
+								x;
+
+							i.removeClass('polyfill-placeholder');
+
+							switch (this.type) {
+
+								case 'submit':
+								case 'reset':
+									break;
+
+								case 'password':
+									i.val(i.attr('defaultValue'));
+
+									x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
+
+									if (i.val() == '') {
+										i.hide();
+										x.show();
+									}
+									else {
+										i.show();
+										x.hide();
+									}
+
+									break;
+
+								case 'checkbox':
+								case 'radio':
+									i.attr('checked', i.attr('defaultValue'));
+									break;
+
+								case 'text':
+								case 'textarea':
+									i.val(i.attr('defaultValue'));
+
+									if (i.val() == '') {
+										i.addClass('polyfill-placeholder');
+										i.val(i.attr('placeholder'));
+									}
+
+									break;
+
+								default:
+									i.val(i.attr('defaultValue'));
+									break;
+
+							}
+						});
+
+				});
+
+		return $this;
+
+	};
+
+	/**
+	 * Moves elements to/from the first positions of their respective parents.
+	 * @param {jQuery} $elements Elements (or selector) to move.
+	 * @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations.
+	 */
+	$.prioritize = function($elements, condition) {
+
+		var key = '__prioritize';
+
+		// Expand $elements if it's not already a jQuery object.
+			if (typeof $elements != 'jQuery')
+				$elements = $($elements);
+
+		// Step through elements.
+			$elements.each(function() {
+
+				var	$e = $(this), $p,
+					$parent = $e.parent();
+
+				// No parent? Bail.
+					if ($parent.length == 0)
+						return;
+
+				// Not moved? Move it.
+					if (!$e.data(key)) {
+
+						// Condition is false? Bail.
+							if (!condition)
+								return;
+
+						// Get placeholder (which will serve as our point of reference for when this element needs to move back).
+							$p = $e.prev();
+
+							// Couldn't find anything? Means this element's already at the top, so bail.
+								if ($p.length == 0)
+									return;
+
+						// Move element to top of parent.
+							$e.prependTo($parent);
+
+						// Mark element as moved.
+							$e.data(key, $p);
+
+					}
+
+				// Moved already?
+					else {
+
+						// Condition is true? Bail.
+							if (condition)
+								return;
+
+						$p = $e.data(key);
+
+						// Move element back to its original location (using our placeholder).
+							$e.insertAfter($p);
+
+						// Unmark element as moved.
+							$e.removeData(key);
+
+					}
+
+			});
+
+	};
+
+})(jQuery);

+ 6 - 0
templates/assets/svg/git.svg

@@ -0,0 +1,6 @@
+<svg t="1691372442425" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2279"
+    width="170" height="200">
+    <path
+        d="M512 0C229.23264 0 0 229.23264 0 512c0 282.76736 229.23264 512 512 512 51.623253 0 101.451093-7.673173 148.43904-21.886293 127.91808-38.68672 234.666667-126.07488 298.707627-240.59904 25.78432-46.107307 44.632747-96.610987 55.166293-150.09792 0.054613-0.273067 0.12288-0.53248 0.177493-0.805547C1020.7232 578.70336 1024 545.737387 1024 512 1024 229.23264 794.76736 0 512 0zM823.958187 542.180693l-281.750187 281.750187c-16.329387 16.308907-42.769067 16.308907-59.06432 0L215.69536 556.516693l-12.192427-12.192427-3.46112-3.46112c-16.308907-16.308907-16.308907-42.728107 0-59.057493l132.87424-132.860587 0.34816-0.34816 54.12864-54.114987 49.493333 49.493333c-3.80928 7.92576-5.9392 16.820907-5.9392 26.200747 0 26.48064 16.91648 48.96768 40.523093 57.316693l0 169.04192c-23.606613 8.349013-40.523093 30.856533-40.523093 57.316693 0 33.573547 27.211093 60.78464 60.78464 60.78464s60.78464-27.211093 60.78464-60.78464c0-26.48064-16.923307-48.96768-40.523093-57.316693L511.993173 427.47904c2.02752-0.709973 4.007253-1.51552 5.9392-2.450773l81.025707 81.025707c-3.80928 7.92576-5.9392 16.820907-5.9392 26.200747 0 33.573547 27.211093 60.78464 60.78464 60.78464 33.573547 0 60.78464-27.211093 60.78464-60.78464 0-33.573547-27.211093-60.78464-60.78464-60.78464-9.37984 0-18.254507 2.1504-26.200747 5.9392L546.583893 396.383573c3.80928-7.92576 5.9392-16.820907 5.9392-26.200747 0-33.573547-27.211093-60.78464-60.78464-60.78464-9.37984 0-18.254507 2.1504-26.200747 5.9392l-49.493333-49.493333 27.613867-27.613867 0.211627-0.211627 10.67008-10.67008 27.27936-27.27936c16.329387-16.308907 42.769067-16.308907 59.057493 0l76.32896 76.322133 19.203413 19.196587 187.55584 187.542187 0-0.02048C840.267093 499.411627 840.267093 525.871787 823.958187 542.180693z"
+        p-id="2280" fill="#c79cc8"></path>
+</svg>

+ 6 - 0
templates/assets/svg/github.svg

@@ -0,0 +1,6 @@
+<svg t="1690797645233" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4051"
+    width="200" height="200">
+    <path
+        d="M511.6 76.3C264.3 76.2 64 276.4 64 523.5 64 718.9 189.3 885 363.8 946c23.5 5.9 19.9-10.8 19.9-22.2v-77.5c-135.7 15.9-141.2-73.9-150.3-88.9C215 726 171.5 718 184.5 703c30.9-15.9 62.4 4 98.9 57.9 26.4 39.1 77.9 32.5 104 26 5.7-23.5 17.9-44.5 34.7-60.8-140.6-25.2-199.2-111-199.2-213 0-49.5 16.3-95 48.3-131.7-20.4-60.5 1.9-112.3 4.9-120 58.1-5.2 118.5 41.6 123.2 45.3 33-8.9 70.7-13.6 112.9-13.6 42.4 0 80.2 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.3-43.9 2.9 7.7 24.7 58.3 5.5 118 32.4 36.8 48.9 82.7 48.9 132.3 0 102.2-59 188.1-200 212.9 23.5 23.2 38.1 55.4 38.1 91v112.5c0.8 9 0 17.9 15 17.9 177.1-59.7 304.6-227 304.6-424.1 0-247.2-200.4-447.3-447.5-447.3z"
+        p-id="4052" fill="#a89cc8"></path>
+</svg>

+ 6 - 0
templates/assets/svg/qq.svg

@@ -0,0 +1,6 @@
+<svg t="1690858551765" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3417"
+    width="200" height="200">
+    <path
+        d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64z m210.5 612.4c-11.5 1.4-44.9-52.7-44.9-52.7 0 31.3-16.2 72.2-51.1 101.8 16.9 5.2 54.9 19.2 45.9 34.4-7.3 12.3-125.6 7.9-159.8 4-34.2 3.8-152.5 8.3-159.8-4-9.1-15.2 28.9-29.2 45.8-34.4-35-29.5-51.1-70.4-51.1-101.8 0 0-33.4 54.1-44.9 52.7-5.4-0.7-12.4-29.6 9.4-99.7 10.3-33 22-60.5 40.2-105.8-3.1-116.9 45.3-215 160.4-215 113.9 0 163.3 96.1 160.4 215 18.1 45.2 29.9 72.8 40.2 105.8 21.7 70.1 14.6 99.1 9.3 99.7z"
+        p-id="3418" fill="#efa8b0"></path>
+</svg>

+ 24 - 8
templates/autoindex.html

@@ -2,17 +2,13 @@
 <html>
 <head>
     <title>Index of {{ path }}</title>
-    <style>
-        body { font-family: sans-serif; }
-        a { text-decoration: none; color: #0366d6; }
-        a:hover { text-decoration: underline; }
-        table { width: 100%; border-collapse: collapse; }
-        th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
-    </style>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
+    <link rel="stylesheet" href="/assets/css/main.css" />
 </head>
 <body>
     <h1>Index of {{ path }}</h1>
-    <table>
+    <table class="file-table">
         <thead>
             <tr>
                 <th>Name</th>
@@ -30,5 +26,25 @@
             {% endfor %}
         </tbody>
     </table>
+
+    <!-- Footer -->
+    <footer id="footer">
+        <p class="copyright">
+            联系我们:contact@dragonos.org
+            <br />
+            <a href="https://github.com/DragonOS-Community/mirror-proxy", target="_blank">
+                完善此页面
+            </a>
+        </p>
+        <p class="copyright" style="margin-top: 0">
+            ©2022-2025 DragonOS Community
+            <br />
+            All rights reserved.
+        </p>
+    </footer>
+
+    <!-- Scripts -->
+    <script src="/assets/js/jquery.min.js"></script>
+    <!-- <script src="/assets/js/main.js"></script> -->
 </body>
 </html>

+ 213 - 0
templates/index.html

@@ -0,0 +1,213 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>DragonOS官方镜像站</title>
+    <meta charset="utf-8" />
+    <meta
+      name="viewport"
+      content="width=device-width, initial-scale=1, user-scalable=no"
+    />
+    <link rel="stylesheet" href="assets/css/main.css" />
+    <noscript
+      ><link rel="stylesheet" href="assets/css/noscript.css"
+    /></noscript>
+  </head>
+  <body class="is-preload">
+    <!-- Wrapper -->
+    <div id="wrapper">
+      <!-- Header -->
+      <header id="header" class="alt">
+        <h1>DragonOS 镜像站</h1>
+        <p>DragonOS is a Light-weight kernel for serverless computing.</p>
+      </header>
+
+      <!-- Nav -->
+      <nav id="nav">
+        <ul>
+          <li><a href="#first" class="active">资源中心</a></li>
+          <li><a href="#second">了解更多</a></li>
+          <li><a href="#cta">赞助我们</a></li>
+        </ul>
+      </nav>
+
+      <!-- Main -->
+      <div id="main">
+        <!-- First Section -->
+        <section id="first" class="main special">
+          <header class="major">
+            <h2>DragonOS 资源中心</h2>
+            <p class="subtitle">获取DragonOS最新版本和资源</p>
+          </header>
+          <div class="content">
+            <div class="download-info">
+              <div class="download-item">
+                <h3>官网</h3>
+                <p>
+                  点击访问
+                  <a href="https://dragonos.org"
+                    >dragonos.org</a
+                  >了解更多信息。
+                </p>
+              </div>
+              <div class="download-item">
+                <h3>文件下载</h3>
+                <p>
+                  访问
+                  <a href="/pub/">mirrors.dragonos.org/pub/</a>
+                  获取DragonOS各版本的代码和镜像文件
+                </p>
+              </div>
+            </div>
+          </div>
+        </section>
+
+        <!-- Second Section -->
+        <section id="second" class="main special">
+          <header class="major">
+            <h2>了解更多</h2>
+          </header>
+          <ul class="features">
+            <li>
+              <a
+                style="border-bottom: none"
+                href="https://github.com/DragonOS-Community/DragonOS"
+              >
+                <span class="icon style3">
+                  <img
+                    src="/assets/svg/github.svg"
+                    alt="github
+				  "
+                  />
+                </span>
+              </a>
+              <h3>GitHub仓库</h3>
+              <a href="https://github.com/DragonOS-Community/DragonOS"
+                >github.com/DragonOS-Community/DragonOS</a
+              >
+            </li>
+            <li>
+              <a
+                style="border-bottom: none"
+                href="https://git.mirrors.dragonos.org"
+              >
+                <span class="icon style2">
+                  <img src="/assets/svg/git.svg" alt="git mirror" />
+                </span>
+              </a>
+              <h3>Git镜像站</h3>
+              <a href="https://git.mirrors.dragonos.org"
+                >git.mirrors.dragonos.org</a
+              >
+            </li>
+
+            <li>
+              <a
+                style="border-bottom: none"
+                href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=5KfmkHtFRxR0Cs0UY2Nuq-C2KBJHUR1k&authKey=b%2BXKM94Z%2FIKrZScWaLQOIlvi4wXtGjrVBRhCamN8%2FWY8Rt9WVt2%2FkQvyWHOP9fL7&noverify=0&group_code=115763565"
+              >
+                <span class="icon style1">
+                  <img src="/assets/svg/qq.svg" alt="QQ群二维码" />
+                </span>
+              </a>
+              <h3>开发交流QQ群</h3>
+              <a
+                href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=5KfmkHtFRxR0Cs0UY2Nuq-C2KBJHUR1k&authKey=b%2BXKM94Z%2FIKrZScWaLQOIlvi4wXtGjrVBRhCamN8%2FWY8Rt9WVt2%2FkQvyWHOP9fL7&noverify=0&group_code=115763565"
+                >115763565</a
+              >
+            </li>
+          </ul>
+          <footer class="major">
+            <ul class="actions special" style="list-style: none">
+              <li style="list-style: none">
+                <a
+                  href="https://github.com/DragonOS-Community/DragonOS"
+                  class="button cta-button"
+                  target="_blank"
+                  rel="noopener noreferrer"
+                >立即加入我们</a
+                >
+              </li>
+            </ul>
+          </footer>
+        </section>
+
+        <!-- Get Started -->
+        <section id="cta" class="main special">
+          <header class="major">
+            <h2>赞助DragonOS</h2>
+            <p>
+              DragonOS的发展离不开资金的支持,我们保证,所有赞助的资金及物品,将会用于:
+            </p>
+            <ul style="width: 40%; margin: auto; list-style: none">
+              <li>为活跃的社区开发者发放补贴或设备支持</li>
+              <li>DragonOS的云服务开支</li>
+              <li>设备购置</li>
+              <li>任何有助于DragonOS发展的用途</li>
+            </ul>
+          </header>
+          <footer class="major">
+            <ul class="actions special">
+              <li>
+                <a href="https://dragonos.org/?page_id=37" class="button"
+                  >前往赞助</a
+                >
+              </li>
+            </ul>
+          </footer>
+          <header class="major">
+            <h2>赞助商</h2>
+            <ul class="features">
+              <li>
+                <a style="border-bottom: none" href="https://yacloud.net">
+                  <span class="icon style3">
+                    <img
+                      decoding="async"
+                      width="300px"
+                      height="auto"
+                      src="https://dragonos.org/wp-content/uploads/2023/11/雅云logo-缩略图-300x69.png"
+                      alt=""
+                      class="wp-image-15"
+                      srcset="
+                        https://dragonos.org/wp-content/uploads/2023/11/雅云logo-缩略图-300x69.png 1024w,
+                        https://dragonos.org/wp-content/uploads/2023/11/雅云logo-缩略图-300x69.png  300w,
+                        https://dragonos.org/wp-content/uploads/2023/11/雅云logo-缩略图-300x69.png  768w,
+                        https://dragonos.org/wp-content/uploads/2023/11/雅云logo-缩略图-300x69.png 1536w,
+                        https://dragonos.org/wp-content/uploads/2023/11/雅云logo-缩略图-300x69.png 2048w
+                      "
+                    />
+                  </span>
+                </a>
+                <br />
+              </li>
+            </ul>
+          </header>
+        </section>
+      </div>
+
+      <!-- Footer -->
+      <footer id="footer">
+        <p class="copyright">
+          联系我们:contact@dragonos.org
+          <br />
+          <a href="https://github.com/DragonOS-Community/mirror-proxy", target="_blank">
+            完善此页面
+          </a>
+        </p>
+        <p class="copyright" style="margin-top: 0">
+          ©2022-2025 DragonOS Community
+          <br />
+          All rights reserved.
+        </p>
+      </footer>
+    </div>
+
+    <!-- Scripts -->
+    <script src="assets/js/jquery.min.js"></script>
+    <script src="assets/js/jquery.scrollex.min.js"></script>
+    <script src="assets/js/jquery.scrolly.min.js"></script>
+    <script src="assets/js/browser.min.js"></script>
+    <script src="assets/js/breakpoints.min.js"></script>
+    <script src="assets/js/util.js"></script>
+    <script src="assets/js/main.js"></script>
+  </body>
+</html>

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.