Spaces:
Running
Running
Upload 13 files
Browse files- index.html +122 -46
- style.css +20 -9
index.html
CHANGED
|
@@ -21,9 +21,9 @@
|
|
| 21 |
box-shadow: 0 2px 20px rgba(0,0,0,0.3) !important;
|
| 22 |
}
|
| 23 |
|
| 24 |
-
header {
|
| 25 |
-
margin-top:
|
| 26 |
-
}
|
| 27 |
|
| 28 |
.history-container {
|
| 29 |
padding-bottom: 20px !important;
|
|
@@ -31,13 +31,13 @@
|
|
| 31 |
|
| 32 |
/* 调整输入区内部布局 */
|
| 33 |
.control-bar {
|
| 34 |
-
max-width:
|
| 35 |
margin: 0 auto;
|
| 36 |
padding: 12px 20px !important;
|
| 37 |
}
|
| 38 |
|
| 39 |
.preview-bar {
|
| 40 |
-
max-width:
|
| 41 |
margin: 0 auto;
|
| 42 |
padding: 0 20px;
|
| 43 |
}
|
|
@@ -47,9 +47,9 @@
|
|
| 47 |
}
|
| 48 |
|
| 49 |
/* 动态调整header间距 */
|
| 50 |
-
.has-preview header {
|
| 51 |
-
margin-top:
|
| 52 |
-
}
|
| 53 |
|
| 54 |
@media (max-width: 768px) {
|
| 55 |
header {
|
|
@@ -167,13 +167,17 @@
|
|
| 167 |
<div class="modal-img-area">
|
| 168 |
<img id="m-img" src="">
|
| 169 |
</div>
|
| 170 |
-
<div class="modal-footer">
|
| 171 |
-
<div class="input-refs" id="m-refs"></div>
|
| 172 |
-
<div class="prompt-display" id="m-prompt"></div>
|
| 173 |
-
<
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
</div>
|
| 178 |
</div>
|
| 179 |
|
|
@@ -685,7 +689,7 @@
|
|
| 685 |
init() {
|
| 686 |
this.container = document.getElementById('gallery');
|
| 687 |
this.loadMoreBtn = document.getElementById('gallery-load-more');
|
| 688 |
-
this.pageSize = Device.isMobile ?
|
| 689 |
this.visibleCount = this.pageSize;
|
| 690 |
if (this.loadMoreBtn) {
|
| 691 |
this.loadMoreBtn.onclick = () => this.loadMore();
|
|
@@ -722,7 +726,7 @@
|
|
| 722 |
|
| 723 |
loadMore() {
|
| 724 |
const total = AppState.galleryData.length;
|
| 725 |
-
if (!total) return;
|
| 726 |
const scroller = this.container ? this.container.closest('.history-container') : null;
|
| 727 |
const scrollTop = scroller ? scroller.scrollTop : window.scrollY;
|
| 728 |
this.visibleCount = Math.min(total, (this.visibleCount || this.pageSize) + this.pageSize);
|
|
@@ -960,19 +964,23 @@
|
|
| 960 |
// ============================================
|
| 961 |
// 弹窗管理模块
|
| 962 |
// ============================================
|
| 963 |
-
const ModalManager = {
|
| 964 |
-
modal: null,
|
| 965 |
-
imgEl: null,
|
| 966 |
-
promptEl: null,
|
| 967 |
-
refsEl: null,
|
| 968 |
-
reuseBtn: null,
|
| 969 |
-
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
this.
|
| 974 |
-
this.
|
| 975 |
-
this.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 976 |
|
| 977 |
// 点击背景关闭
|
| 978 |
this.modal.onclick = (e) => {
|
|
@@ -1006,16 +1014,27 @@
|
|
| 1006 |
});
|
| 1007 |
}
|
| 1008 |
|
| 1009 |
-
// 绑定复用按钮
|
| 1010 |
-
this.reuseBtn.onclick = () => this.reuse();
|
| 1011 |
-
|
| 1012 |
-
|
| 1013 |
-
|
| 1014 |
-
|
| 1015 |
-
|
| 1016 |
-
|
| 1017 |
-
|
| 1018 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1019 |
|
| 1020 |
reuse() {
|
| 1021 |
const item = AppState.currentModalItem;
|
|
@@ -1034,10 +1053,41 @@
|
|
| 1034 |
ImageHandler.clear();
|
| 1035 |
}
|
| 1036 |
|
| 1037 |
-
this.close();
|
| 1038 |
-
textarea.focus();
|
| 1039 |
-
}
|
| 1040 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1041 |
|
| 1042 |
// ============================================
|
| 1043 |
// 公共画廊管理模块
|
|
@@ -1066,7 +1116,7 @@
|
|
| 1066 |
this.refreshBtn = document.getElementById('refresh-public-gallery');
|
| 1067 |
this.hintEl = document.getElementById('public-gallery-hint');
|
| 1068 |
this.loadMoreBtn = document.getElementById('public-gallery-load-more');
|
| 1069 |
-
this.pageSize = Device.isMobile ?
|
| 1070 |
this.visibleCount = this.pageSize;
|
| 1071 |
this.tokens = this.loadTokens();
|
| 1072 |
if (this.hintEl && this.hintEl.textContent) {
|
|
@@ -1081,9 +1131,35 @@
|
|
| 1081 |
this.loadMoreBtn.onclick = () => this.loadMore();
|
| 1082 |
}
|
| 1083 |
|
|
|
|
| 1084 |
this.initialFetch();
|
| 1085 |
},
|
| 1086 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1087 |
resetPagination() {
|
| 1088 |
this.visibleCount = this.pageSize;
|
| 1089 |
},
|
|
@@ -1114,7 +1190,7 @@
|
|
| 1114 |
|
| 1115 |
loadMore() {
|
| 1116 |
const total = AppState.publicGalleryData.length;
|
| 1117 |
-
if (!total) return;
|
| 1118 |
const scroller = this.container ? this.container.closest('.history-container') : null;
|
| 1119 |
const scrollTop = scroller ? scroller.scrollTop : window.scrollY;
|
| 1120 |
this.visibleCount = Math.min(total, (this.visibleCount || this.pageSize) + this.pageSize);
|
|
|
|
| 21 |
box-shadow: 0 2px 20px rgba(0,0,0,0.3) !important;
|
| 22 |
}
|
| 23 |
|
| 24 |
+
header {
|
| 25 |
+
margin-top: 115px; /* 为输入区留空间 */
|
| 26 |
+
}
|
| 27 |
|
| 28 |
.history-container {
|
| 29 |
padding-bottom: 20px !important;
|
|
|
|
| 31 |
|
| 32 |
/* 调整输入区内部布局 */
|
| 33 |
.control-bar {
|
| 34 |
+
max-width: 1400px;
|
| 35 |
margin: 0 auto;
|
| 36 |
padding: 12px 20px !important;
|
| 37 |
}
|
| 38 |
|
| 39 |
.preview-bar {
|
| 40 |
+
max-width: 1400px;
|
| 41 |
margin: 0 auto;
|
| 42 |
padding: 0 20px;
|
| 43 |
}
|
|
|
|
| 47 |
}
|
| 48 |
|
| 49 |
/* 动态调整header间距 */
|
| 50 |
+
.has-preview header {
|
| 51 |
+
margin-top: 260px;
|
| 52 |
+
}
|
| 53 |
|
| 54 |
@media (max-width: 768px) {
|
| 55 |
header {
|
|
|
|
| 167 |
<div class="modal-img-area">
|
| 168 |
<img id="m-img" src="">
|
| 169 |
</div>
|
| 170 |
+
<div class="modal-footer">
|
| 171 |
+
<div class="input-refs" id="m-refs"></div>
|
| 172 |
+
<div class="prompt-display" id="m-prompt"></div>
|
| 173 |
+
<div class="modal-actions">
|
| 174 |
+
<button class="icon-btn" id="m-fullscreen" title="全屏查看" aria-label="全屏查看">全屏</button>
|
| 175 |
+
<button class="icon-btn" id="m-download" title="保存图片" aria-label="保存图片">保存</button>
|
| 176 |
+
</div>
|
| 177 |
+
<button class="btn-3d" id="m-reuse" style="width: 100%; padding: 12px;">
|
| 178 |
+
复用参数与图片
|
| 179 |
+
</button>
|
| 180 |
+
</div>
|
| 181 |
</div>
|
| 182 |
</div>
|
| 183 |
|
|
|
|
| 689 |
init() {
|
| 690 |
this.container = document.getElementById('gallery');
|
| 691 |
this.loadMoreBtn = document.getElementById('gallery-load-more');
|
| 692 |
+
this.pageSize = Device.isMobile ? 12 : 12;
|
| 693 |
this.visibleCount = this.pageSize;
|
| 694 |
if (this.loadMoreBtn) {
|
| 695 |
this.loadMoreBtn.onclick = () => this.loadMore();
|
|
|
|
| 726 |
|
| 727 |
loadMore() {
|
| 728 |
const total = AppState.galleryData.length;
|
| 729 |
+
if (!total || this.visibleCount >= total) return;
|
| 730 |
const scroller = this.container ? this.container.closest('.history-container') : null;
|
| 731 |
const scrollTop = scroller ? scroller.scrollTop : window.scrollY;
|
| 732 |
this.visibleCount = Math.min(total, (this.visibleCount || this.pageSize) + this.pageSize);
|
|
|
|
| 964 |
// ============================================
|
| 965 |
// 弹窗管理模块
|
| 966 |
// ============================================
|
| 967 |
+
const ModalManager = {
|
| 968 |
+
modal: null,
|
| 969 |
+
imgEl: null,
|
| 970 |
+
promptEl: null,
|
| 971 |
+
refsEl: null,
|
| 972 |
+
reuseBtn: null,
|
| 973 |
+
fullscreenBtn: null,
|
| 974 |
+
downloadBtn: null,
|
| 975 |
+
|
| 976 |
+
init() {
|
| 977 |
+
this.modal = document.getElementById('modal');
|
| 978 |
+
this.imgEl = document.getElementById('m-img');
|
| 979 |
+
this.promptEl = document.getElementById('m-prompt');
|
| 980 |
+
this.refsEl = document.getElementById('m-refs');
|
| 981 |
+
this.reuseBtn = document.getElementById('m-reuse');
|
| 982 |
+
this.fullscreenBtn = document.getElementById('m-fullscreen');
|
| 983 |
+
this.downloadBtn = document.getElementById('m-download');
|
| 984 |
|
| 985 |
// 点击背景关闭
|
| 986 |
this.modal.onclick = (e) => {
|
|
|
|
| 1014 |
});
|
| 1015 |
}
|
| 1016 |
|
| 1017 |
+
// 绑定复用按钮
|
| 1018 |
+
this.reuseBtn.onclick = () => this.reuse();
|
| 1019 |
+
if (this.fullscreenBtn) {
|
| 1020 |
+
this.fullscreenBtn.onclick = () => this.toggleFullscreen();
|
| 1021 |
+
}
|
| 1022 |
+
if (this.downloadBtn) {
|
| 1023 |
+
this.downloadBtn.onclick = () => this.downloadCurrent();
|
| 1024 |
+
}
|
| 1025 |
+
|
| 1026 |
+
this.modal.style.display = 'flex';
|
| 1027 |
+
},
|
| 1028 |
+
|
| 1029 |
+
close() {
|
| 1030 |
+
this.modal.style.display = 'none';
|
| 1031 |
+
AppState.currentModalItem = null;
|
| 1032 |
+
if (document.fullscreenElement && document.exitFullscreen) {
|
| 1033 |
+
document.exitFullscreen();
|
| 1034 |
+
} else if (document.webkitFullscreenElement && document.webkitExitFullscreen) {
|
| 1035 |
+
document.webkitExitFullscreen();
|
| 1036 |
+
}
|
| 1037 |
+
},
|
| 1038 |
|
| 1039 |
reuse() {
|
| 1040 |
const item = AppState.currentModalItem;
|
|
|
|
| 1053 |
ImageHandler.clear();
|
| 1054 |
}
|
| 1055 |
|
| 1056 |
+
this.close();
|
| 1057 |
+
textarea.focus();
|
| 1058 |
+
},
|
| 1059 |
+
|
| 1060 |
+
toggleFullscreen() {
|
| 1061 |
+
const target = this.modal;
|
| 1062 |
+
if (!target) return;
|
| 1063 |
+
if (document.fullscreenElement || document.webkitFullscreenElement) {
|
| 1064 |
+
if (document.exitFullscreen) {
|
| 1065 |
+
document.exitFullscreen();
|
| 1066 |
+
} else if (document.webkitExitFullscreen) {
|
| 1067 |
+
document.webkitExitFullscreen();
|
| 1068 |
+
}
|
| 1069 |
+
return;
|
| 1070 |
+
}
|
| 1071 |
+
if (target.requestFullscreen) {
|
| 1072 |
+
target.requestFullscreen();
|
| 1073 |
+
} else if (target.webkitRequestFullscreen) {
|
| 1074 |
+
target.webkitRequestFullscreen();
|
| 1075 |
+
}
|
| 1076 |
+
},
|
| 1077 |
+
|
| 1078 |
+
downloadCurrent() {
|
| 1079 |
+
const item = AppState.currentModalItem;
|
| 1080 |
+
if (!item) return;
|
| 1081 |
+
const src = ImageHandler.getDisplayImage(item) || item.image || item.imageUrl || item.thumb;
|
| 1082 |
+
if (!src) return;
|
| 1083 |
+
const link = document.createElement('a');
|
| 1084 |
+
link.href = src;
|
| 1085 |
+
link.download = `banana-pro-${item.id || Date.now()}.png`;
|
| 1086 |
+
document.body.appendChild(link);
|
| 1087 |
+
link.click();
|
| 1088 |
+
document.body.removeChild(link);
|
| 1089 |
+
}
|
| 1090 |
+
};
|
| 1091 |
|
| 1092 |
// ============================================
|
| 1093 |
// 公共画廊管理模块
|
|
|
|
| 1116 |
this.refreshBtn = document.getElementById('refresh-public-gallery');
|
| 1117 |
this.hintEl = document.getElementById('public-gallery-hint');
|
| 1118 |
this.loadMoreBtn = document.getElementById('public-gallery-load-more');
|
| 1119 |
+
this.pageSize = Device.isMobile ? 12 : 12;
|
| 1120 |
this.visibleCount = this.pageSize;
|
| 1121 |
this.tokens = this.loadTokens();
|
| 1122 |
if (this.hintEl && this.hintEl.textContent) {
|
|
|
|
| 1131 |
this.loadMoreBtn.onclick = () => this.loadMore();
|
| 1132 |
}
|
| 1133 |
|
| 1134 |
+
this.bindAutoLoad();
|
| 1135 |
this.initialFetch();
|
| 1136 |
},
|
| 1137 |
|
| 1138 |
+
bindAutoLoad() {
|
| 1139 |
+
if (!Device.isMobile || this.autoLoadBound) return;
|
| 1140 |
+
const scroller = document.querySelector('.history-container');
|
| 1141 |
+
if (!scroller) return;
|
| 1142 |
+
this.autoLoadBound = true;
|
| 1143 |
+
this.scroller = scroller;
|
| 1144 |
+
this.autoLoading = false;
|
| 1145 |
+
|
| 1146 |
+
const onScroll = () => {
|
| 1147 |
+
if (this.autoLoading) return;
|
| 1148 |
+
const total = (AppState.publicGalleryData || []).length;
|
| 1149 |
+
if (!total || this.visibleCount >= total) return;
|
| 1150 |
+
const nearBottom = scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - 240;
|
| 1151 |
+
if (!nearBottom) return;
|
| 1152 |
+
this.autoLoading = true;
|
| 1153 |
+
this.loadMore();
|
| 1154 |
+
setTimeout(() => {
|
| 1155 |
+
this.autoLoading = false;
|
| 1156 |
+
}, 120);
|
| 1157 |
+
};
|
| 1158 |
+
|
| 1159 |
+
scroller.addEventListener('scroll', onScroll, { passive: true });
|
| 1160 |
+
this.autoLoadHandler = onScroll;
|
| 1161 |
+
},
|
| 1162 |
+
|
| 1163 |
resetPagination() {
|
| 1164 |
this.visibleCount = this.pageSize;
|
| 1165 |
},
|
|
|
|
| 1190 |
|
| 1191 |
loadMore() {
|
| 1192 |
const total = AppState.publicGalleryData.length;
|
| 1193 |
+
if (!total || this.visibleCount >= total) return;
|
| 1194 |
const scroller = this.container ? this.container.closest('.history-container') : null;
|
| 1195 |
const scrollTop = scroller ? scroller.scrollTop : window.scrollY;
|
| 1196 |
this.visibleCount = Math.min(total, (this.visibleCount || this.pageSize) + this.pageSize);
|
style.css
CHANGED
|
@@ -156,7 +156,7 @@ body {
|
|
| 156 |
|
| 157 |
/* --- Layout --- */
|
| 158 |
.app-container {
|
| 159 |
-
max-width:
|
| 160 |
margin: 0 auto;
|
| 161 |
width: 100%;
|
| 162 |
height: 100%;
|
|
@@ -314,7 +314,7 @@ header h2 {
|
|
| 314 |
|
| 315 |
|
| 316 |
body.has-preview header {
|
| 317 |
-
margin-top:
|
| 318 |
}
|
| 319 |
|
| 320 |
/* --- History Gallery --- */
|
|
@@ -1188,16 +1188,27 @@ body.has-preview header {
|
|
| 1188 |
}
|
| 1189 |
}
|
| 1190 |
|
| 1191 |
-
.modal-footer {
|
| 1192 |
-
padding: 20px;
|
| 1193 |
-
background: rgba(30, 41, 59, 0.95);
|
| 1194 |
backdrop-filter: blur(16px);
|
| 1195 |
border-top: 1px solid var(--panel-border-strong);
|
| 1196 |
display: flex;
|
| 1197 |
-
flex-direction: column;
|
| 1198 |
-
gap: 12px;
|
| 1199 |
-
border-radius: 0 0 20px 20px;
|
| 1200 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1201 |
|
| 1202 |
.input-refs {
|
| 1203 |
display: flex;
|
|
|
|
| 156 |
|
| 157 |
/* --- Layout --- */
|
| 158 |
.app-container {
|
| 159 |
+
max-width: 1400px;
|
| 160 |
margin: 0 auto;
|
| 161 |
width: 100%;
|
| 162 |
height: 100%;
|
|
|
|
| 314 |
|
| 315 |
|
| 316 |
body.has-preview header {
|
| 317 |
+
margin-top: 260px;
|
| 318 |
}
|
| 319 |
|
| 320 |
/* --- History Gallery --- */
|
|
|
|
| 1188 |
}
|
| 1189 |
}
|
| 1190 |
|
| 1191 |
+
.modal-footer {
|
| 1192 |
+
padding: 20px;
|
| 1193 |
+
background: rgba(30, 41, 59, 0.95);
|
| 1194 |
backdrop-filter: blur(16px);
|
| 1195 |
border-top: 1px solid var(--panel-border-strong);
|
| 1196 |
display: flex;
|
| 1197 |
+
flex-direction: column;
|
| 1198 |
+
gap: 12px;
|
| 1199 |
+
border-radius: 0 0 20px 20px;
|
| 1200 |
+
}
|
| 1201 |
+
|
| 1202 |
+
.modal-actions {
|
| 1203 |
+
display: flex;
|
| 1204 |
+
gap: 10px;
|
| 1205 |
+
flex-wrap: wrap;
|
| 1206 |
+
}
|
| 1207 |
+
|
| 1208 |
+
.modal-actions .icon-btn {
|
| 1209 |
+
min-width: 110px;
|
| 1210 |
+
height: 36px;
|
| 1211 |
+
}
|
| 1212 |
|
| 1213 |
.input-refs {
|
| 1214 |
display: flex;
|