1 parent
cc5d61af16
commit
0ce95688d5
15 files changed
+5016
-990
No files matched your search
@@ -1,308 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>墨水屏倒计时 Pro - 动态阵列版</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
||||
<style>
|
||||
:root { --ep-black: #000000; --ep-red: #ff0000; --ep-white: #ffffff; }
|
||||
body { font-family: "PingFang SC", "STHeiti", sans-serif; background: #f0f2f5; display: flex; flex-direction: column; align-items: center; padding: 20px; gap: 20px; }
|
||||
|
||||
/* --- 4.2寸预览区 (400x300) --- */
|
||||
#capture-area {
|
||||
width: 400px; height: 300px;
|
||||
background: var(--ep-white);
|
||||
border: 1px solid #000;
|
||||
display: flex; flex-direction: column;
|
||||
box-sizing: border-box; overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.top-date {
|
||||
position: absolute;
|
||||
top: 8px; right: 12px;
|
||||
font-size: 10px;
|
||||
color: var(--ep-black);
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
line-height: 1.2;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: left;
|
||||
padding: 12px 0 8px 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#title-text {
|
||||
color: var(--ep-black);
|
||||
border-left: 5px solid var(--ep-red);
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
font-weight: 900;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* --- 阵列布局容器 --- */
|
||||
.exam-grid-preview {
|
||||
padding: 0 12px 12px 12px;
|
||||
flex-grow: 1;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
align-content: stretch;
|
||||
}
|
||||
|
||||
/* --- 矩形卡片样式 --- */
|
||||
.preview-card {
|
||||
border: 2px solid var(--ep-black);
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
background: white;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.is-important-card {
|
||||
border: 4px solid var(--ep-red) !important;
|
||||
}
|
||||
.is-important-card::after {
|
||||
content: "★";
|
||||
position: absolute;
|
||||
top: 4px; right: 6px;
|
||||
color: var(--ep-red);
|
||||
}
|
||||
|
||||
.preview-name {
|
||||
font-weight: bold;
|
||||
color: var(--ep-black);
|
||||
margin-bottom: 5px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.preview-days-info {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.preview-days-val {
|
||||
font-weight: 900;
|
||||
color: var(--ep-red);
|
||||
font-family: 'Arial Black', sans-serif;
|
||||
line-height: 1;
|
||||
}
|
||||
.preview-unit {
|
||||
font-weight: bold;
|
||||
color: var(--ep-black);
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
/* --- 管理区 --- */
|
||||
.admin-panel { width: 520px; background: white; padding: 20px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
|
||||
.input-card { display: flex; gap: 8px; margin-bottom: 15px; align-items: center; background: #f8f9fa; padding: 12px; border-radius: 8px; }
|
||||
.input-card input { padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
|
||||
|
||||
#sortable-list { list-style: none; padding: 0; margin: 0; }
|
||||
.manage-item {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
background: #fff; border: 1px solid #eee; margin-bottom: 8px;
|
||||
padding: 10px; border-radius: 6px; cursor: move;
|
||||
}
|
||||
.drag-handle { color: #ccc; cursor: grab; font-size: 20px; user-select: none; }
|
||||
.manage-info { flex-grow: 1; display: flex; gap: 8px; }
|
||||
.manage-info input[type="text"] { flex: 2; }
|
||||
.btn-del { background: #ff4d4f; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; }
|
||||
|
||||
.action-btns { display: flex; gap: 10px; margin-top: 20px; }
|
||||
.btn-main { flex: 1; padding: 12px; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; }
|
||||
.btn-save { background: var(--ep-red); color: white; }
|
||||
.btn-data { background: #555; color: white; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="capture-area">
|
||||
<div class="top-date" id="live-date"></div>
|
||||
<div class="header">
|
||||
<h1 id="title-text">倒计时看板</h1>
|
||||
</div>
|
||||
<div class="exam-grid-preview" id="preview-container"></div>
|
||||
</div>
|
||||
|
||||
<div class="admin-panel">
|
||||
<h3 style="margin-top:0; border-left: 4px solid var(--ep-red); padding-left: 10px;">项目管理</h3>
|
||||
|
||||
<div class="input-card">
|
||||
<input type="text" id="name-in" placeholder="项目名称">
|
||||
<input type="date" id="date-in">
|
||||
<label style="font-size:13px; cursor:pointer"><input type="checkbox" id="imp-in"> 重要</label>
|
||||
<button onclick="addItem()" style="background:#000; color:white; border:none; padding:8px 15px; border-radius:4px; cursor:pointer">添加</button>
|
||||
</div>
|
||||
|
||||
<ul id="sortable-list"></ul>
|
||||
|
||||
<div class="action-btns">
|
||||
<button class="btn-main btn-data" onclick="exportJSON()">备份</button>
|
||||
<button class="btn-main btn-data" onclick="document.getElementById('file-in').click()">恢复</button>
|
||||
<input type="file" id="file-in" style="display:none" onchange="importJSON(this)">
|
||||
<button class="btn-main btn-save" onclick="downloadImage()">保存 400x300 图片</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const getTodayStr = () => new Date().toISOString().split('T')[0];
|
||||
|
||||
let exams = JSON.parse(localStorage.getItem('dragExamGridV2')) || [
|
||||
{ name: "期末大考", date: "2026-06-20", imp: true },
|
||||
{ name: "驾照预约", date: getTodayStr(), imp: false }
|
||||
];
|
||||
|
||||
function updateLiveDate() {
|
||||
const now = new Date();
|
||||
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||||
document.getElementById('live-date').innerHTML = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日<br>${weekDays[now.getDay()]}`;
|
||||
}
|
||||
|
||||
Sortable.create(document.getElementById('sortable-list'), {
|
||||
animation: 150, handle: '.drag-handle', onEnd: () => saveOrder()
|
||||
});
|
||||
|
||||
function calculateDays(targetDate) {
|
||||
const today = new Date().setHours(0,0,0,0);
|
||||
const target = new Date(targetDate).setHours(0,0,0,0);
|
||||
const diff = target - today;
|
||||
return Math.ceil(diff / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
function renderAll() {
|
||||
renderPreview();
|
||||
renderManageList();
|
||||
updateLiveDate();
|
||||
localStorage.setItem('dragExamGridV2', JSON.stringify(exams));
|
||||
}
|
||||
|
||||
function renderPreview() {
|
||||
const container = document.getElementById('preview-container');
|
||||
container.innerHTML = '';
|
||||
const count = exams.length;
|
||||
|
||||
// 1. 动态确定网格布局
|
||||
let cols = 2;
|
||||
if (count === 1) cols = 1;
|
||||
else if (count > 4) cols = 3;
|
||||
container.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
|
||||
|
||||
// 2. 根据数量动态计算字体大小 (单位 px)
|
||||
// 逻辑:项目越少,字号越大
|
||||
let baseNameSize, baseNumSize, starSize;
|
||||
if (count <= 1) {
|
||||
baseNameSize = 64; baseNumSize = 80; starSize = 36;
|
||||
} else if (count <= 2) {
|
||||
baseNameSize = 24; baseNumSize = 64; starSize = 20;
|
||||
} else if (count <= 4) {
|
||||
baseNameSize = 18; baseNumSize = 48; starSize = 16;
|
||||
} else {
|
||||
baseNameSize = 14; baseNumSize = 32; starSize = 14;
|
||||
}
|
||||
|
||||
exams.forEach(item => {
|
||||
const days = calculateDays(item.date);
|
||||
let dayHTML = '';
|
||||
|
||||
if (days === 0) {
|
||||
dayHTML = `<span class="preview-days-val" style="font-size:${baseNumSize * 0.6}px">今天</span>`;
|
||||
} else if (days < 0) {
|
||||
dayHTML = `<span class="preview-days-val" style="font-size:${baseNumSize * 0.6}px; color:#666">已过</span>`;
|
||||
} else {
|
||||
dayHTML = `<span class="preview-days-val" style="font-size:${baseNumSize}px">${days}</span>
|
||||
<span class="preview-unit" style="font-size:${baseNumSize * 0.3}px">天</span>`;
|
||||
}
|
||||
|
||||
container.innerHTML += `
|
||||
<div class="preview-card ${item.imp ? 'is-important-card' : ''}">
|
||||
${item.imp ? `<style>.is-important-card::after{font-size:${starSize}px}</style>` : ''}
|
||||
<div class="preview-name" style="font-size:${baseNameSize}px">${item.name}</div>
|
||||
<div class="preview-days-info">
|
||||
${dayHTML}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
function renderManageList() {
|
||||
const list = document.getElementById('sortable-list');
|
||||
list.innerHTML = '';
|
||||
exams.forEach((item, index) => {
|
||||
list.innerHTML += `
|
||||
<li class="manage-item" data-index="${index}">
|
||||
<span class="drag-handle">☰</span>
|
||||
<div class="manage-info">
|
||||
<input type="text" value="${item.name}" onchange="updateItem(${index}, 'name', this.value)">
|
||||
<input type="date" value="${item.date}" onchange="updateItem(${index}, 'date', this.value)">
|
||||
<label><input type="checkbox" ${item.imp?'checked':''} onchange="updateItem(${index}, 'imp', this.checked)"> 重要</label>
|
||||
</div>
|
||||
<button class="btn-del" onclick="removeItem(${index})">×</button>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
}
|
||||
function updateItem(index, key, value) {
|
||||
exams[index][key] = value;
|
||||
renderPreview();
|
||||
localStorage.setItem('dragExamGridV2', JSON.stringify(exams));
|
||||
}
|
||||
function saveOrder() {
|
||||
const newExams = [];
|
||||
document.querySelectorAll('.manage-item').forEach(el => {
|
||||
newExams.push(exams[el.getAttribute('data-index')]);
|
||||
});
|
||||
exams = newExams;
|
||||
renderAll();
|
||||
}
|
||||
function addItem() {
|
||||
const n = document.getElementById('name-in').value;
|
||||
const d = document.getElementById('date-in').value;
|
||||
const i = document.getElementById('imp-in').checked;
|
||||
if(n && d) {
|
||||
exams.push({name:n, date:d, imp:i});
|
||||
renderAll();
|
||||
document.getElementById('name-in').value = '';
|
||||
}
|
||||
}
|
||||
function removeItem(index) {
|
||||
exams.splice(index, 1);
|
||||
renderAll();
|
||||
}
|
||||
function downloadImage() {
|
||||
html2canvas(document.getElementById('capture-area'), { width: 400, height: 300, scale: 2 })
|
||||
.then(canvas => {
|
||||
const link = document.createElement('a');
|
||||
link.download = `Grid_Countdown.png`;
|
||||
link.href = canvas.toDataURL();
|
||||
link.click();
|
||||
});
|
||||
}
|
||||
function exportJSON() {
|
||||
const blob = new Blob([JSON.stringify(exams)], {type: 'application/json'});
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob); a.download = 'exams.json'; a.click();
|
||||
}
|
||||
function importJSON(input) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => { exams = JSON.parse(e.target.result); renderAll(); };
|
||||
reader.readAsText(input.files[0]);
|
||||
}
|
||||
renderAll();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,218 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>墨水屏标语倒计时 - 红黑版</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
||||
<style>
|
||||
:root { --ep-black: #000000; --ep-red: #ff0000; --ep-white: #ffffff; }
|
||||
body { font-family: "PingFang SC", "Microsoft YaHei", sans-serif; background: #f4f4f4; display: flex; flex-direction: column; align-items: center; padding: 30px; }
|
||||
|
||||
/* --- 4.2寸预览区 (400x300) --- */
|
||||
#capture-area {
|
||||
width: 400px; height: 300px;
|
||||
background: var(--ep-white);
|
||||
border: 2px solid #000;
|
||||
display: flex; flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box; overflow: hidden;
|
||||
position: relative;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 顶部日期栏 */
|
||||
.top-date {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
color: var(--ep-black);
|
||||
letter-spacing: 1px;
|
||||
border-bottom: 1px solid var(--ep-black);
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/* 核心标语区 - 居中特大号 */
|
||||
.motto-section {
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
#editable-motto {
|
||||
font-size: 42px; /* 进一步放大 */
|
||||
font-weight: 900;
|
||||
color: var(--ep-black);
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
line-height: 1.1;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* 分割点 */
|
||||
.dot-divider {
|
||||
margin: 15px 0;
|
||||
font-size: 20px;
|
||||
color: var(--ep-red);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 倒计时展示区 */
|
||||
.countdown-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.event-label {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
color: #444;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.days-container {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.days-num {
|
||||
font-size: 85px; /* 巨型数字 */
|
||||
font-family: 'Arial Black', sans-serif;
|
||||
font-weight: 900;
|
||||
line-height: 0.85;
|
||||
color: var(--ep-red); /* 改为红色 */
|
||||
}
|
||||
|
||||
.days-unit {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: var(--ep-black);
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* 管理面板 */
|
||||
.admin-panel {
|
||||
width: 400px; background: white; padding: 25px;
|
||||
border-radius: 12px; margin-top: 20px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
}
|
||||
.input-item { margin-bottom: 15px; display: flex; flex-direction: column; gap: 5px; }
|
||||
.input-item label { font-size: 13px; font-weight: bold; color: #666; }
|
||||
.input-item input { padding: 10px; border: 1px solid #ccc; border-radius: 6px; }
|
||||
|
||||
.btn-save {
|
||||
width: 100%; padding: 12px; border: none; border-radius: 6px;
|
||||
font-weight: bold; cursor: pointer; background: var(--ep-red); color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="capture-area">
|
||||
<div class="top-date" id="live-date">2026 / 04 / 17 FRIDAY</div>
|
||||
|
||||
<div class="motto-section">
|
||||
<h1 id="editable-motto" onclick="editMotto()" title="点击修改标语">新婚快乐</h1>
|
||||
</div>
|
||||
|
||||
<div class="dot-divider">✦ ✦ ✦</div>
|
||||
|
||||
<div class="countdown-section" id="countdown-display">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-panel">
|
||||
<div class="input-item">
|
||||
<label>目标事件描述</label>
|
||||
<input type="text" id="event-name" placeholder="例如:距离考研/周年庆">
|
||||
</div>
|
||||
<div class="input-item">
|
||||
<label>目标日期</label>
|
||||
<input type="date" id="target-date">
|
||||
</div>
|
||||
|
||||
<button class="btn-save" onclick="saveImage()">下载 400x300 图片</button>
|
||||
<p style="font-size:12px; color:#999; text-align:center; margin-top:12px">提示:直接点击图片中的“黑色大字”可改写标语</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let config = JSON.parse(localStorage.getItem('ep_red_cfg')) || {
|
||||
motto: "保持热爱",
|
||||
label: "距离考研",
|
||||
date: "2026-12-21"
|
||||
};
|
||||
|
||||
function init() {
|
||||
// 填充表单默认值
|
||||
document.getElementById('event-name').value = config.label;
|
||||
document.getElementById('target-date').value = config.date;
|
||||
render();
|
||||
updateDate();
|
||||
}
|
||||
|
||||
function updateDate() {
|
||||
const n = new Date();
|
||||
const weeks = ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY'];
|
||||
document.getElementById('live-date').innerText = `${n.getFullYear()} / ${String(n.getMonth()+1).padStart(2,'0')} / ${String(n.getDate()).padStart(2,'0')} ${weeks[n.getDay()]}`;
|
||||
}
|
||||
|
||||
function editMotto() {
|
||||
const val = prompt("请输入顶端大标语:", config.motto);
|
||||
if (val) {
|
||||
config.motto = val;
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
const label = document.getElementById('event-name').value || "距离目标";
|
||||
const date = document.getElementById('target-date').value || "2026-12-31";
|
||||
|
||||
// 更新配置
|
||||
config.label = label;
|
||||
config.date = date;
|
||||
document.getElementById('editable-motto').innerText = config.motto;
|
||||
|
||||
const target = new Date(date).setHours(0,0,0,0);
|
||||
const today = new Date().setHours(0,0,0,0);
|
||||
const diff = Math.ceil((target - today) / (1000 * 60 * 60 * 24));
|
||||
|
||||
let displayNum = diff;
|
||||
let unit = "DAYS";
|
||||
|
||||
if (diff === 0) { displayNum = "0"; }
|
||||
else if (diff < 0) { displayNum = "!"; unit = "OVER"; }
|
||||
|
||||
document.getElementById('countdown-display').innerHTML = `
|
||||
<div class="event-label">${label}</div>
|
||||
<div class="days-container">
|
||||
<span class="days-num">${displayNum}</span>
|
||||
<span class="days-unit">${unit}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
localStorage.setItem('ep_red_cfg', JSON.stringify(config));
|
||||
}
|
||||
|
||||
// 监听输入
|
||||
document.getElementById('event-name').addEventListener('input', render);
|
||||
document.getElementById('target-date').addEventListener('input', render);
|
||||
|
||||
function saveImage() {
|
||||
html2canvas(document.getElementById('capture-area'), {
|
||||
width: 400,
|
||||
height: 300,
|
||||
scale: 2
|
||||
}).then(canvas => {
|
||||
const a = document.createElement('a');
|
||||
a.download = `EInk_Countdown_Red.png`;
|
||||
a.href = canvas.toDataURL();
|
||||
a.click();
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,619 @@
|
||||
:root {
|
||||
--primary-color: #0d6efd;
|
||||
--primary-hover: #0b5ed7;
|
||||
--secondary-color: #6c757d;
|
||||
--secondary-hover: #5c636a;
|
||||
|
||||
--dark-bg: #121212;
|
||||
--dark-text: #e0e0e0;
|
||||
--dark-fieldset-bg: #1e1e1e;
|
||||
--dark-border: #333;
|
||||
--dark-code-bg: #2d2d2d;
|
||||
--dark-log-bg: #2a2a2a;
|
||||
--dark-input-bg: #2d2d2d;
|
||||
--dark-input-text: #e0e0e0;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.375rem 0.75rem;
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 0.375rem;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
button.primary {
|
||||
color: #fff;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
button.primary:hover {
|
||||
color: #fff;
|
||||
border-color: var(--primary-hover);
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
button.secondary {
|
||||
color: #fff;
|
||||
background-color: var(--secondary-color);
|
||||
border-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
button.secondary:hover {
|
||||
color: #fff;
|
||||
border-color: var(--secondary-hover);
|
||||
background-color: var(--secondary-hover);
|
||||
}
|
||||
|
||||
h3 {
|
||||
padding-bottom: .3em;
|
||||
border-bottom: 1px solid #ccc;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: none;
|
||||
box-shadow: 0 .5rem 0.5rem rgba(0, 0, 0, 0.2);
|
||||
background-color: #f8f9fa;
|
||||
padding: 10px;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
fieldset legend {
|
||||
font-weight: bold;
|
||||
color: rgba(0, 0, 255, 0.6);
|
||||
}
|
||||
|
||||
code {
|
||||
padding: .2em .4em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background: #ccc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
input[type=text],
|
||||
input[type=date],
|
||||
input[type=number],
|
||||
select {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.375rem;
|
||||
padding: .2rem .75rem;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input[type=file] {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
input::file-selector-button {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
border: 1px solid var(--primary-color);
|
||||
border-radius: 0.375rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: .3rem 2.25rem .3rem .75rem;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
select:focus {
|
||||
border: 1px solid #86b7fe;
|
||||
box-shadow: 0 0 4px rgba(0, 120, 215, 0.8);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input[type=text]:disabled,
|
||||
input[type=date]:disabled,
|
||||
input[type=number]:disabled,
|
||||
select:disabled {
|
||||
opacity: 0.65;
|
||||
cursor: not-allowed;
|
||||
background-color: #e9ecef;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-right: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
max-width: 950px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
background: #fff;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
flex-wrap: wrap;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.footer .links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer .links a {
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.footer .links a:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.footer .links a:not(:last-child)::after {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.footer a:hover {
|
||||
color: #0d6efd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.flex-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-group.right {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.debug {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.log-container {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
max-height: 300px;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
background: #ddd;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;
|
||||
box-sizing: border-box;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.log-container .log-line {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.log-container .time,
|
||||
.log-container .action {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.log-container .time {
|
||||
color: #333;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.log-container .action {
|
||||
color: #666;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.template-panel {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.5rem;
|
||||
background: #fff;
|
||||
padding: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.panel-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.panel-tab {
|
||||
color: #495057;
|
||||
background: #eef2f6;
|
||||
border-color: #d0d7de;
|
||||
}
|
||||
|
||||
.panel-tab:hover {
|
||||
background: #dde5ee;
|
||||
border-color: #c1c9d2;
|
||||
}
|
||||
|
||||
.panel-tab.active {
|
||||
color: #fff;
|
||||
background: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.panel-tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.panel-tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.template-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: baseline;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.template-header span {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.template-mode-panel {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.template-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.template-item {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.375rem;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.template-item input[type="text"] {
|
||||
min-width: 120px;
|
||||
flex: 1 1 160px;
|
||||
}
|
||||
|
||||
.template-item input[type="date"] {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.template-item label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.canvas-container canvas {
|
||||
border: black solid 1px;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.canvas-container.crop-mode canvas {
|
||||
border: 2px dashed var(--primary-color);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
display: none;
|
||||
font-size: 85%;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px dotted #AAA;
|
||||
}
|
||||
|
||||
canvas.text-placement-mode {
|
||||
border: 2px dashed var(--primary-color) !important;
|
||||
cursor: text !important;
|
||||
}
|
||||
|
||||
.canvas-title {
|
||||
display: none;
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.canvas-tools {
|
||||
margin-top: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.brush-tools,
|
||||
.text-tools,
|
||||
.crop-tools {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.canvas-container.brush-mode .brush-tools,
|
||||
.canvas-container.text-mode .brush-tools,
|
||||
.canvas-container.eraser-mode .brush-tools,
|
||||
.canvas-container.text-mode .text-tools,
|
||||
.canvas-container.crop-mode .crop-tools {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.canvas-container.crop-mode .tool-buttons,
|
||||
.canvas-container.crop-mode .brush-tools,
|
||||
.canvas-container.crop-mode .text-tools {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tool-button {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 1.2rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 5px;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.tool-button:hover {
|
||||
background-color: #e9ecef;
|
||||
border-color: #ced4da;
|
||||
}
|
||||
|
||||
.tool-button.active {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.tool-button.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.flex-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.panel-tabs {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.panel-tab {
|
||||
flex: 1 1 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.flex-container.options .flex-group label {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.flex-group.right {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.canvas-tools.flex-container {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.canvas-tools .flex-group {
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.log-container {
|
||||
height: 150px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
input[type=text],
|
||||
input[type=number],
|
||||
select {
|
||||
max-width: 100%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
body.dark-mode .debug {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
body.dark-mode,
|
||||
body.dark-mode .main {
|
||||
background-color: var(--dark-bg);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
body.dark-mode fieldset {
|
||||
background-color: var(--dark-fieldset-bg);
|
||||
box-shadow: 0 .5rem 0.5rem rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode h3 {
|
||||
border-bottom: 1px solid var(--dark-border);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
body.dark-mode code {
|
||||
background: var(--dark-code-bg);
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
body.dark-mode input[type=text],
|
||||
body.dark-mode input[type=date],
|
||||
body.dark-mode input[type=number],
|
||||
body.dark-mode select {
|
||||
background-color: var(--dark-input-bg);
|
||||
color: var(--dark-input-text);
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
body.dark-mode input[type=text]:disabled,
|
||||
body.dark-mode input[type=date]:disabled,
|
||||
body.dark-mode input[type=number]:disabled,
|
||||
body.dark-mode select:disabled {
|
||||
background-color: #1a1a1a;
|
||||
color: #666;
|
||||
border-color: #2a2a2a;
|
||||
}
|
||||
|
||||
body.dark-mode input[type=file] {
|
||||
color: var(--dark-input-text);
|
||||
background-color: transparent;
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
body.dark-mode input[type=file]::file-selector-button {
|
||||
background-color: var(--dark-fieldset-bg);
|
||||
color: var(--dark-input-text);
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
body.dark-mode input[type=file]::file-selector-button:hover {
|
||||
background-color: #333;
|
||||
border-color: #444;
|
||||
}
|
||||
|
||||
body.dark-mode .log-container {
|
||||
background: var(--dark-log-bg);
|
||||
border: 1px solid var(--dark-border);
|
||||
}
|
||||
|
||||
body.dark-mode .log-container .time {
|
||||
color: #8bc34a;
|
||||
}
|
||||
|
||||
body.dark-mode .log-container .action {
|
||||
color: #03a9f4;
|
||||
}
|
||||
|
||||
body.dark-mode fieldset legend {
|
||||
color: #64b5f6;
|
||||
}
|
||||
|
||||
body.dark-mode .footer .links a:not(:last-child)::after {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
body.dark-mode .footer {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
body.dark-mode .footer a {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
body.dark-mode .footer a:hover {
|
||||
color: #64b5f6;
|
||||
}
|
||||
|
||||
body.dark-mode .tool-button {
|
||||
background-color: var(--dark-input-bg);
|
||||
border-color: var(--dark-border);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
body.dark-mode .tool-button:hover {
|
||||
background-color: #3a3a3a;
|
||||
border-color: #444;
|
||||
}
|
||||
|
||||
body.dark-mode .tool-button.active {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
body.dark-mode .template-panel,
|
||||
body.dark-mode .template-item {
|
||||
background-color: var(--dark-fieldset-bg);
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
body.dark-mode .panel-tab {
|
||||
color: var(--dark-text);
|
||||
background-color: #2a2a2a;
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
body.dark-mode .panel-tab:hover {
|
||||
background-color: #333;
|
||||
border-color: #444;
|
||||
}
|
||||
|
||||
body.dark-mode .panel-tab.active {
|
||||
background-color: var(--primary-color);
|
||||
border-color: var(--primary-hover);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.dark-mode .template-header span {
|
||||
color: #aaa;
|
||||
}
|
||||
Loaded 3 of 15 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user