mirror of
https://gitcode.com/Zengtudor/EnvEditorWebview.git
synced 2025-06-02 03:47:24 +00:00
update
This commit is contained in:
parent
6d1fb82a35
commit
bdbd170acf
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
constexpr const char* html = R"(
|
||||
constexpr const inline char* html = R"(
|
||||
@HTML_CONTENT@
|
||||
)";
|
444
src/index.html
444
src/index.html
@ -5,61 +5,334 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Environment Variables Viewer</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, sans-serif; margin: 0; background: #f5f7fa; }
|
||||
.container { max-width: 1200px; margin: 0 auto; padding: 0 16px; }
|
||||
header { background: white; padding: 20px 0; box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
|
||||
h1 { color: #165DFF; margin: 0; }
|
||||
main { padding: 24px 0; }
|
||||
.card { background: white; border-radius: 8px; box-shadow: 0 2px 5px rgba(0,0,0,0.05); padding: 16px; }
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
th { text-align: left; padding: 12px 16px; background: #f9fafb; color: #6b7280; font-size: 12px; text-transform: uppercase; }
|
||||
td { padding: 12px 16px; border-bottom: 1px solid #e5e7eb; }
|
||||
tr:last-child td { border-bottom: none; }
|
||||
tr:nth-child(even) { background: #f9fafb; }
|
||||
tr:hover { background: #f3f4f6; }
|
||||
footer { background: #1d2129; color: white; text-align: center; padding: 20px 0; }
|
||||
.loading { text-align: center; color: #9ca3af; padding: 20px 0; }
|
||||
.error { text-align: center; color: #ef4444; padding: 20px 0; }
|
||||
a { color: #165DFF; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
:root {
|
||||
--primary-color: #165DFF;
|
||||
--primary-hover: #0E42CC;
|
||||
--primary-active: #0A3199;
|
||||
--neutral-light: #F5F7FA;
|
||||
--neutral-medium: #E5E7EB;
|
||||
--neutral-dark: #6B7280;
|
||||
--text-primary: #1D2129;
|
||||
--text-secondary: #4E5969;
|
||||
--success: #36D399;
|
||||
--error: #EF4444;
|
||||
--warning: #FBBF24;
|
||||
--info: #3B82F6;
|
||||
--transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--neutral-light);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
header {
|
||||
background: white;
|
||||
padding: 1.5rem 0;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
||||
margin-bottom: 1.5rem;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
header .container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--primary-color);
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
header p {
|
||||
color: var(--neutral-dark);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.05), 0 4px 6px -2px rgba(0, 0, 0, 0.03);
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.07), 0 10px 10px -5px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.btn {
|
||||
background-color: #165DFF;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.375rem;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
transition: var(--transition);
|
||||
box-shadow: 0 4px 6px -1px rgba(22, 93, 255, 0.1), 0 2px 4px -1px rgba(22, 93, 255, 0.06);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #0E42CC;
|
||||
background-color: var(--primary-hover);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 10px 15px -3px rgba(22, 93, 255, 0.15), 0 4px 6px -2px rgba(22, 93, 255, 0.08);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
background-color: #0A3199;
|
||||
background-color: var(--primary-active);
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 4px -1px rgba(22, 93, 255, 0.1);
|
||||
}
|
||||
|
||||
.btn::before {
|
||||
content: "↻";
|
||||
display: inline-block;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.btn.loading::before {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--neutral-light);
|
||||
color: var(--neutral-dark);
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid var(--neutral-medium);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.75rem 1rem;
|
||||
border-bottom: 1px solid var(--neutral-medium);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background: var(--neutral-light);
|
||||
}
|
||||
|
||||
tr {
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background: rgba(22, 93, 255, 0.05);
|
||||
}
|
||||
|
||||
footer {
|
||||
background: var(--text-primary);
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 1.5rem 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
footer a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
footer a:hover {
|
||||
border-bottom-color: white;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
color: var(--neutral-dark);
|
||||
padding: 2rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loading::before {
|
||||
content: "";
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border: 2px solid var(--neutral-medium);
|
||||
border-radius: 50%;
|
||||
border-top-color: var(--primary-color);
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.error {
|
||||
text-align: center;
|
||||
color: var(--error);
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
max-height: 80px;
|
||||
max-height: 5rem;
|
||||
overflow-y: auto;
|
||||
max-width: 300px;
|
||||
border: 1px solid #e5e7eb;
|
||||
padding: 4px;
|
||||
border-radius: 2px;
|
||||
background-color: #f9fafb;
|
||||
max-width: 100%;
|
||||
border: 1px solid var(--neutral-medium);
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--neutral-light);
|
||||
font-family: monospace;
|
||||
font-size: 0.875rem;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
/* 自定义滚动条样式 */
|
||||
|
||||
/* 自定义滚动条 */
|
||||
.scrollable::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
width: 0.375rem;
|
||||
}
|
||||
|
||||
.scrollable::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
background: var(--neutral-light);
|
||||
border-radius: 0.1875rem;
|
||||
}
|
||||
|
||||
.scrollable::-webkit-scrollbar-thumb {
|
||||
background: #c5c5c5;
|
||||
border-radius: 3px;
|
||||
background: var(--neutral-medium);
|
||||
border-radius: 0.1875rem;
|
||||
}
|
||||
|
||||
.scrollable::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
background: var(--neutral-dark);
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.env-key {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.env-value {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 640px) {
|
||||
.container {
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
max-height: 3.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
right: 0.25rem;
|
||||
background: rgba(22, 93, 255, 0.1);
|
||||
color: var(--primary-color);
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
background: rgba(22, 93, 255, 0.2);
|
||||
}
|
||||
|
||||
.value-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.value-container:hover .copy-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.copy-success {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
right: 0.25rem;
|
||||
background: var(--success);
|
||||
color: white;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0;
|
||||
transition: var(--transition);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.copy-success.show {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@ -73,7 +346,7 @@
|
||||
|
||||
<main class="container">
|
||||
<button id="refreshBtn" class="btn">
|
||||
<i class="fa fa-refresh mr-1"></i> Refresh
|
||||
Refresh
|
||||
</button>
|
||||
<div class="card">
|
||||
<table id="envTable">
|
||||
@ -104,40 +377,126 @@
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
// 禁用右键菜单
|
||||
document.addEventListener('contextmenu', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
async function refreshEnvTable() {
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
const tableBody = document.getElementById('envTableBody');
|
||||
tableBody.innerHTML = '<tr><td colspan="2" class="loading">Refreshing environment variables...</td></tr>';
|
||||
|
||||
// 显示加载状态
|
||||
tableBody.innerHTML = '<tr><td colspan="2" class="loading">Refreshing environment variables...</td></tr>';
|
||||
refreshBtn.classList.add('loading');
|
||||
refreshBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const env = await window.getEnvString();
|
||||
|
||||
// 清空表格
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
// 检查是否有环境变量
|
||||
if (!env || Object.keys(env).length === 0) {
|
||||
tableBody.innerHTML = '<tr><td colspan="2" class="loading">No environment variables found</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加环境变量行
|
||||
Object.entries(env).forEach(([key, value]) => {
|
||||
const row = document.createElement('tr');
|
||||
row.className = 'fade-in';
|
||||
row.innerHTML = `
|
||||
<td>${key}</td>
|
||||
<td><div class="scrollable" title="${value}">${value}</div></td>
|
||||
<td class="env-key">${key}</td>
|
||||
<td>
|
||||
<div class="value-container">
|
||||
<div class="scrollable env-value" title="${value}">${value}</div>
|
||||
<button class="copy-btn" data-value="${value}">Copy</button>
|
||||
<div class="copy-success">Copied!</div>
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
|
||||
// 添加复制功能
|
||||
document.querySelectorAll('.copy-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
const value = this.getAttribute('data-value');
|
||||
|
||||
// 改进的复制功能,增加兼容性处理
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(value).then(() => {
|
||||
showCopySuccess(this.nextElementSibling);
|
||||
}).catch(err => {
|
||||
console.error('Failed to copy using Clipboard API: ', err);
|
||||
fallbackCopyTextToClipboard(value, this.nextElementSibling);
|
||||
});
|
||||
} else {
|
||||
fallbackCopyTextToClipboard(value, this.nextElementSibling);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
tableBody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="2" class="error">Failed to load: ${error.message}</td>
|
||||
</tr>
|
||||
`;
|
||||
} finally {
|
||||
// 恢复按钮状态
|
||||
refreshBtn.classList.remove('loading');
|
||||
refreshBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示复制成功消息
|
||||
function showCopySuccess(successMsg) {
|
||||
successMsg.classList.add('show');
|
||||
setTimeout(() => {
|
||||
successMsg.classList.remove('show');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 备选复制方法
|
||||
function fallbackCopyTextToClipboard(text, successMsg) {
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = text;
|
||||
|
||||
// 使 textarea 不在视窗内,防止影响布局
|
||||
textArea.style.position = "fixed";
|
||||
textArea.style.top = "-9999px";
|
||||
textArea.style.left = "-9999px";
|
||||
document.body.appendChild(textArea);
|
||||
|
||||
// 选中并复制文本
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
const successful = document.execCommand('copy');
|
||||
if (successful) {
|
||||
showCopySuccess(successMsg);
|
||||
} else {
|
||||
console.error('Fallback: Copying text command failed');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Fallback: Oops, unable to copy', err);
|
||||
}
|
||||
|
||||
// 移除 textarea
|
||||
document.body.removeChild(textArea);
|
||||
}
|
||||
|
||||
// 页面加载完成后刷新环境变量
|
||||
document.addEventListener('DOMContentLoaded', refreshEnvTable);
|
||||
|
||||
// 点击刷新按钮
|
||||
document.getElementById('refreshBtn').addEventListener('click', refreshEnvTable);
|
||||
|
||||
// Mock data for demonstration
|
||||
// 模拟数据
|
||||
if (!window.getEnvString) {
|
||||
window.getEnvString = async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
@ -155,5 +514,4 @@
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user