feat: 添加跨平台打包支持(Linux .deb)、Docker 构建脚本及项目官网
- electron/builder.js: 修复 Linux 平台 npm 命令、增加 .deb 安装包支持 - electron/main.js: 按平台动态设置保存对话框默认扩展名 - package.json: 添加 Linux deb 打包目标 - 新增 Dockerfile 用于 Linux 交叉构建 - 新增 build-linux-docker.ps1 / build-linux.sh 构建脚本 - 新增 site/ 项目官网页面 - .gitignore: 全面忽略二进制文件 - 新增 GitHub Actions CI 工作流
This commit is contained in:
58
.github/workflows/build.yml
vendored
Normal file
58
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
name: Build Web2App
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build
|
||||||
|
- run: npx electron-builder --config --win
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Web2App-Windows
|
||||||
|
path: release/*.exe
|
||||||
|
|
||||||
|
build-macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build
|
||||||
|
- run: npx electron-builder --config --mac
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Web2App-macOS
|
||||||
|
path: release/*.dmg
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y rpm libx11-dev libxkbfile-dev libsecret-1-dev
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build
|
||||||
|
- run: npx electron-builder --config --linux
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Web2App-Linux
|
||||||
|
path: |
|
||||||
|
release/*.AppImage
|
||||||
|
release/*.deb
|
||||||
81
.gitignore
vendored
81
.gitignore
vendored
@@ -1,6 +1,87 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
.web2app/
|
.web2app/
|
||||||
|
release/
|
||||||
|
|
||||||
|
# Binaries & executables
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.bin
|
||||||
|
*.pak
|
||||||
|
*.dat
|
||||||
|
|
||||||
|
# Disk images & installers
|
||||||
|
*.dmg
|
||||||
|
*.iso
|
||||||
|
*.img
|
||||||
|
*.AppImage
|
||||||
|
*.deb
|
||||||
|
*.rpm
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
*.zip
|
||||||
|
*.7z
|
||||||
|
*.tar
|
||||||
|
*.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# Images (binary formats)
|
||||||
|
*.ico
|
||||||
|
*.icns
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.gif
|
||||||
|
*.bmp
|
||||||
|
*.webp
|
||||||
|
|
||||||
|
# Documents
|
||||||
|
*.pdf
|
||||||
|
*.doc
|
||||||
|
*.docx
|
||||||
|
*.xls
|
||||||
|
*.xlsx
|
||||||
|
*.ppt
|
||||||
|
*.pptx
|
||||||
|
|
||||||
|
# Audio & Video
|
||||||
|
*.mp3
|
||||||
|
*.mp4
|
||||||
|
*.avi
|
||||||
|
*.mov
|
||||||
|
*.wav
|
||||||
|
*.flac
|
||||||
|
*.mkv
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
*.ttf
|
||||||
|
*.otf
|
||||||
|
*.woff
|
||||||
|
*.woff2
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Object & build artifacts
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.class
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.pdb
|
||||||
|
*.idb
|
||||||
|
|
||||||
|
# Other binary
|
||||||
|
*.snap
|
||||||
|
*.crx
|
||||||
|
|
||||||
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
FROM node:20-bullseye
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
rpm \
|
||||||
|
libx11-dev \
|
||||||
|
libxkbfile-dev \
|
||||||
|
libsecret-1-dev \
|
||||||
|
fakeroot \
|
||||||
|
dpkg-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
RUN npx electron-builder --config --linux
|
||||||
|
|
||||||
|
CMD ["cp", "-r", "release/*", "/output/"]
|
||||||
19
build-linux-docker.ps1
Normal file
19
build-linux-docker.ps1
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Write-Host "===== Web2App Linux Docker Build ====="
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "This script builds the Linux version using Docker."
|
||||||
|
Write-Host "Prerequisites: Docker Desktop with Linux container support"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$imageName = "web2app-linux-builder"
|
||||||
|
|
||||||
|
Write-Host "1. Building Docker image..."
|
||||||
|
docker build -t $imageName .
|
||||||
|
|
||||||
|
Write-Host "2. Running build..."
|
||||||
|
$outputDir = Join-Path (Get-Location) "release-linux"
|
||||||
|
New-Item -ItemType Directory -Force -Path $outputDir
|
||||||
|
docker run --rm -v "${outputDir}:/output" $imageName
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "===== Build Complete ====="
|
||||||
|
Write-Host "Output: $outputDir"
|
||||||
17
build-linux.sh
Normal file
17
build-linux.sh
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "===== Web2App Linux Build Script ====="
|
||||||
|
|
||||||
|
echo "1. Installing dependencies..."
|
||||||
|
npm install
|
||||||
|
|
||||||
|
echo "2. Building frontend..."
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
echo "3. Building Linux package (AppImage + deb)..."
|
||||||
|
npx electron-builder --config --linux
|
||||||
|
|
||||||
|
echo "===== Build Complete ====="
|
||||||
|
echo "Output: release/"
|
||||||
|
ls -lh release/
|
||||||
@@ -94,7 +94,8 @@ async function startPack(projectPath, outputPath, onProgress) {
|
|||||||
onProgress({ stage: 'install', message: '安装依赖 (首次较慢)...', percent: 50 })
|
onProgress({ stage: 'install', message: '安装依赖 (首次较慢)...', percent: 50 })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync('npm.cmd install --production', {
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
||||||
|
execSync(`${npmCmd} install --production`, {
|
||||||
cwd: tempDir,
|
cwd: tempDir,
|
||||||
stdio: 'pipe',
|
stdio: 'pipe',
|
||||||
timeout: 300000
|
timeout: 300000
|
||||||
@@ -155,7 +156,7 @@ async function startPack(projectPath, outputPath, onProgress) {
|
|||||||
let installerPath = null
|
let installerPath = null
|
||||||
if (fs.existsSync(distDir)) {
|
if (fs.existsSync(distDir)) {
|
||||||
const files = fs.readdirSync(distDir)
|
const files = fs.readdirSync(distDir)
|
||||||
.filter(f => f.endsWith('.exe') || f.endsWith('.dmg') || f.endsWith('.AppImage'))
|
.filter(f => f.endsWith('.exe') || f.endsWith('.dmg') || f.endsWith('.AppImage') || f.endsWith('.deb'))
|
||||||
.sort((a, b) => fs.statSync(path.join(distDir, b)).mtimeMs - fs.statSync(path.join(distDir, a)).mtimeMs)
|
.sort((a, b) => fs.statSync(path.join(distDir, b)).mtimeMs - fs.statSync(path.join(distDir, a)).mtimeMs)
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
installerPath = path.join(distDir, files[0])
|
installerPath = path.join(distDir, files[0])
|
||||||
|
|||||||
@@ -70,9 +70,14 @@ ipcMain.handle('dialog:selectIcon', async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('dialog:saveFile', async (_event, options) => {
|
ipcMain.handle('dialog:saveFile', async (_event, options) => {
|
||||||
|
const defaultFilters = process.platform === 'win32'
|
||||||
|
? [{ name: '安装包', extensions: ['exe'] }]
|
||||||
|
: process.platform === 'darwin'
|
||||||
|
? [{ name: '安装包', extensions: ['dmg'] }]
|
||||||
|
: [{ name: '安装包', extensions: ['AppImage', 'deb'] }]
|
||||||
const result = await dialog.showSaveDialog(mainWindow, {
|
const result = await dialog.showSaveDialog(mainWindow, {
|
||||||
defaultPath: options?.defaultPath,
|
defaultPath: options?.defaultPath,
|
||||||
filters: options?.filters || [{ name: '安装包', extensions: ['exe', 'dmg', 'AppImage'] }]
|
filters: options?.filters || defaultFilters
|
||||||
})
|
})
|
||||||
if (!result.canceled && result.filePath) {
|
if (!result.canceled && result.filePath) {
|
||||||
return result.filePath
|
return result.filePath
|
||||||
|
|||||||
14
package.json
14
package.json
@@ -44,8 +44,18 @@
|
|||||||
"icon": null
|
"icon": null
|
||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"target": ["AppImage"],
|
"target": [
|
||||||
"icon": null
|
{
|
||||||
|
"target": "AppImage",
|
||||||
|
"arch": ["x64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": "deb",
|
||||||
|
"arch": ["x64"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"icon": null,
|
||||||
|
"category": "Utility"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
417
site/index.html
Normal file
417
site/index.html
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Web2App - 将网站转化为独立的桌面应用</title>
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
:root {
|
||||||
|
--primary: #4f46e5;
|
||||||
|
--primary-hover: #4338ca;
|
||||||
|
--primary-light: #eef2ff;
|
||||||
|
--primary-glow: rgba(79,70,229,0.15);
|
||||||
|
--bg: #f8fafc;
|
||||||
|
--surface: #ffffff;
|
||||||
|
--border: #e2e8f0;
|
||||||
|
--text: #1e293b;
|
||||||
|
--text-secondary: #64748b;
|
||||||
|
--text-muted: #94a3b8;
|
||||||
|
--radius: 12px;
|
||||||
|
--shadow: 0 1px 3px rgba(0,0,0,0.08);
|
||||||
|
--shadow-md: 0 4px 20px rgba(0,0,0,0.08);
|
||||||
|
--shadow-lg: 0 10px 40px rgba(0,0,0,0.1);
|
||||||
|
--max-width: 1100px;
|
||||||
|
}
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans SC', sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 16px;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
a { color: var(--primary); text-decoration: none; }
|
||||||
|
a:hover { text-decoration: underline; }
|
||||||
|
img { max-width: 100%; }
|
||||||
|
|
||||||
|
.container { max-width: var(--max-width); margin: 0 auto; padding: 0 24px; }
|
||||||
|
|
||||||
|
/* Nav */
|
||||||
|
nav {
|
||||||
|
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
||||||
|
background: rgba(255,255,255,0.85); backdrop-filter: blur(12px);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
nav .container {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
height: 64px;
|
||||||
|
}
|
||||||
|
nav .logo { font-size: 20px; font-weight: 700; color: var(--primary); display: flex; align-items: center; gap: 8px; }
|
||||||
|
nav .logo svg { width: 28px; height: 28px; }
|
||||||
|
nav .nav-links { display: flex; gap: 32px; align-items: center; }
|
||||||
|
nav .nav-links a { color: var(--text-secondary); font-weight: 500; font-size: 15px; transition: color 0.2s; }
|
||||||
|
nav .nav-links a:hover { color: var(--primary); text-decoration: none; }
|
||||||
|
.nav-cta {
|
||||||
|
background: var(--primary); color: #fff !important; padding: 8px 20px;
|
||||||
|
border-radius: 8px; font-weight: 600;
|
||||||
|
}
|
||||||
|
.nav-cta:hover { background: var(--primary-hover) !important; }
|
||||||
|
|
||||||
|
/* Hero */
|
||||||
|
.hero {
|
||||||
|
padding: 140px 0 80px; text-align: center;
|
||||||
|
background: linear-gradient(180deg, var(--primary-light) 0%, var(--bg) 100%);
|
||||||
|
}
|
||||||
|
.hero-badge {
|
||||||
|
display: inline-flex; align-items: center; gap: 6px;
|
||||||
|
background: rgba(79,70,229,0.1); color: var(--primary);
|
||||||
|
padding: 6px 16px; border-radius: 20px; font-size: 14px; font-weight: 600;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 56px; font-weight: 800; line-height: 1.15; letter-spacing: -1px;
|
||||||
|
background: linear-gradient(135deg, var(--primary) 0%, #7c3aed 100%);
|
||||||
|
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
.hero p {
|
||||||
|
font-size: 20px; color: var(--text-secondary); max-width: 640px;
|
||||||
|
margin: 20px auto 36px;
|
||||||
|
}
|
||||||
|
.hero-buttons { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
|
||||||
|
.btn {
|
||||||
|
display: inline-flex; align-items: center; gap: 8px;
|
||||||
|
padding: 14px 32px; border-radius: 10px; font-size: 16px;
|
||||||
|
font-weight: 600; border: none; cursor: pointer;
|
||||||
|
transition: all 0.2s ease; text-decoration: none;
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
background: var(--primary); color: #fff; box-shadow: 0 4px 14px var(--primary-glow);
|
||||||
|
}
|
||||||
|
.btn-primary:hover { background: var(--primary-hover); transform: translateY(-1px); text-decoration: none; }
|
||||||
|
.btn-secondary {
|
||||||
|
background: var(--surface); color: var(--text); border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.btn-secondary:hover { border-color: var(--primary); color: var(--primary); text-decoration: none; }
|
||||||
|
|
||||||
|
/* Sections */
|
||||||
|
section { padding: 80px 0; }
|
||||||
|
.section-label {
|
||||||
|
display: inline-block; font-size: 13px; font-weight: 700; text-transform: uppercase;
|
||||||
|
letter-spacing: 1px; color: var(--primary); margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 36px; font-weight: 700; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.section-sub {
|
||||||
|
font-size: 18px; color: var(--text-secondary); max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Features */
|
||||||
|
#features { text-align: center; }
|
||||||
|
#features .section-sub { margin: 0 auto 48px; }
|
||||||
|
.features-grid {
|
||||||
|
display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 24px; text-align: left;
|
||||||
|
}
|
||||||
|
.feature-card {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius); padding: 32px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.feature-card:hover {
|
||||||
|
border-color: var(--primary); box-shadow: var(--shadow-md); transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
.feature-icon {
|
||||||
|
width: 48px; height: 48px; border-radius: 12px;
|
||||||
|
background: var(--primary-light); color: var(--primary);
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 24px; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.feature-card h3 { font-size: 18px; font-weight: 600; margin-bottom: 8px; }
|
||||||
|
.feature-card p { font-size: 14px; color: var(--text-secondary); line-height: 1.7; }
|
||||||
|
|
||||||
|
/* Workflow */
|
||||||
|
#workflow { background: var(--surface); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||||
|
#workflow .container { text-align: center; }
|
||||||
|
#workflow .section-sub { margin: 0 auto 48px; }
|
||||||
|
.steps { display: flex; gap: 0; justify-content: center; align-items: flex-start; flex-wrap: wrap; }
|
||||||
|
.step {
|
||||||
|
flex: 1; min-width: 180px; max-width: 220px; padding: 0 16px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.step-num {
|
||||||
|
width: 48px; height: 48px; border-radius: 50%;
|
||||||
|
background: var(--primary); color: #fff;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 20px; font-weight: 700; margin: 0 auto 16px;
|
||||||
|
}
|
||||||
|
.step h4 { font-size: 16px; font-weight: 600; margin-bottom: 6px; }
|
||||||
|
.step p { font-size: 14px; color: var(--text-secondary); }
|
||||||
|
.step-arrow {
|
||||||
|
font-size: 24px; color: var(--text-muted);
|
||||||
|
position: absolute; right: -12px; top: 12px;
|
||||||
|
}
|
||||||
|
.steps .step:last-child .step-arrow { display: none; }
|
||||||
|
|
||||||
|
/* Install */
|
||||||
|
#download { text-align: center; }
|
||||||
|
#download .section-sub { margin: 0 auto 48px; }
|
||||||
|
.platforms { display: flex; gap: 20px; justify-content: center; flex-wrap: wrap; }
|
||||||
|
.platform-card {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius); padding: 36px 40px; min-width: 200px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
.platform-card:hover { border-color: var(--primary); box-shadow: var(--shadow-md); transform: translateY(-2px); }
|
||||||
|
.platform-icon { font-size: 40px; margin-bottom: 12px; }
|
||||||
|
.platform-card h4 { font-size: 18px; font-weight: 600; margin-bottom: 4px; }
|
||||||
|
.platform-card .version { font-size: 13px; color: var(--text-muted); margin-bottom: 16px; }
|
||||||
|
.platform-card .btn { width: 100%; justify-content: center; }
|
||||||
|
.platform-card .coming-soon {
|
||||||
|
display: inline-flex; align-items: center; gap: 6px;
|
||||||
|
padding: 14px 32px; border-radius: 10px; font-size: 16px; font-weight: 600;
|
||||||
|
background: #f1f5f9; color: var(--text-muted); cursor: not-allowed; width: 100%; justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Architecture */
|
||||||
|
#architecture { background: var(--surface); border-top: 1px solid var(--border); }
|
||||||
|
#architecture .container { text-align: center; }
|
||||||
|
#architecture .section-sub { margin: 0 auto 48px; }
|
||||||
|
.arch-diagram {
|
||||||
|
display: flex; flex-direction: column; align-items: center; gap: 12px;
|
||||||
|
max-width: 700px; margin: 0 auto;
|
||||||
|
}
|
||||||
|
.arch-box {
|
||||||
|
background: var(--bg); border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius); padding: 20px 32px; width: 100%;
|
||||||
|
font-weight: 600; font-size: 15px;
|
||||||
|
}
|
||||||
|
.arch-box.primary { background: var(--primary-light); border-color: var(--primary); color: var(--primary); }
|
||||||
|
.arch-box .arch-sub {
|
||||||
|
display: flex; gap: 16px; justify-content: center; margin-top: 12px; flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.arch-box .arch-sub span {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
padding: 6px 16px; border-radius: 6px; font-weight: 400; font-size: 13px;
|
||||||
|
}
|
||||||
|
.arch-arrow { color: var(--text-muted); font-size: 20px; }
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
footer {
|
||||||
|
padding: 40px 0; border-top: 1px solid var(--border);
|
||||||
|
text-align: center; color: var(--text-muted); font-size: 14px;
|
||||||
|
}
|
||||||
|
footer .container { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 12px; }
|
||||||
|
footer a { color: var(--text-secondary); }
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.hero h1 { font-size: 36px; }
|
||||||
|
.hero p { font-size: 17px; }
|
||||||
|
section { padding: 60px 0; }
|
||||||
|
.section-title { font-size: 28px; }
|
||||||
|
.features-grid { grid-template-columns: 1fr; }
|
||||||
|
.steps { flex-direction: column; align-items: center; gap: 24px; }
|
||||||
|
.step-arrow { display: none !important; }
|
||||||
|
nav .nav-links a:not(.nav-cta) { display: none; }
|
||||||
|
footer .container { flex-direction: column; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<div class="container">
|
||||||
|
<a href="#" class="logo">
|
||||||
|
<svg viewBox="0 0 28 28" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<rect x="2" y="4" width="24" height="16" rx="3" />
|
||||||
|
<path d="M8 2v4M20 2v4M2 12h24M10 20v4M18 20v4" />
|
||||||
|
</svg>
|
||||||
|
Web2App
|
||||||
|
</a>
|
||||||
|
<div class="nav-links">
|
||||||
|
<a href="#features">功能特性</a>
|
||||||
|
<a href="#workflow">工作流程</a>
|
||||||
|
<a href="#download" class="nav-cta">立即下载</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Hero -->
|
||||||
|
<section class="hero">
|
||||||
|
<div class="container">
|
||||||
|
<div class="hero-badge">
|
||||||
|
<span>v1.0.0</span>
|
||||||
|
</div>
|
||||||
|
<h1>将任意网站<br>转化为独立的桌面应用</h1>
|
||||||
|
<p>导入网站资源,配置应用信息,一键打包为跨平台安装包 —— 无需编写代码,无需配置运行环境。</p>
|
||||||
|
<div class="hero-buttons">
|
||||||
|
<a href="#download" class="btn btn-primary">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
||||||
|
下载安装包
|
||||||
|
</a>
|
||||||
|
<a href="#features" class="btn btn-secondary">了解更多</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Features -->
|
||||||
|
<section id="features">
|
||||||
|
<div class="container">
|
||||||
|
<span class="section-label">功能特性</span>
|
||||||
|
<h2 class="section-title">强大而简洁</h2>
|
||||||
|
<p class="section-sub">从资源导入到打包发布,Web2App 提供一站式的网站转桌面应用解决方案。</p>
|
||||||
|
<div class="features-grid">
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">📦</div>
|
||||||
|
<h3>一键打包</h3>
|
||||||
|
<p>将完整的网站资源(HTML、JS、CSS、图片等)打包为独立的安装包,内置 Electron 运行时,目标机无需任何预装环境。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">🖥️</div>
|
||||||
|
<h3>跨平台支持</h3>
|
||||||
|
<p>一次打包,多平台分发。支持 Windows(.exe)、macOS(.dmg)、Linux(.AppImage)三大桌面平台。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">⚙️</div>
|
||||||
|
<h3>灵活配置</h3>
|
||||||
|
<p>自定义应用名称、图标、版本号、窗口尺寸、作者版权信息,支持指定入口文件和后端服务入口。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">🌐</div>
|
||||||
|
<h3>内嵌后端服务</h3>
|
||||||
|
<p>应用内嵌 HTTP 服务器与 SQLite 数据库,支持运行 Node.js 后端脚本,自动检测端口占用,无需外部 Web 服务器。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">📂</div>
|
||||||
|
<h3>资源管理</h3>
|
||||||
|
<p>以目录树形式管理所有导入资源,支持批量导入、文件增删改、保留目录结构,资源状态一目了然。</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<div class="feature-icon">🔒</div>
|
||||||
|
<h3>离线可用 · 安全可靠</h3>
|
||||||
|
<p>打包过程完全离线,不上传任何数据至外网。生成 SHA256 校验值确保安装包完整性,安装过程引导清晰。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Workflow -->
|
||||||
|
<section id="workflow">
|
||||||
|
<div class="container">
|
||||||
|
<span class="section-label">工作流程</span>
|
||||||
|
<h2 class="section-title">四步完成打包</h2>
|
||||||
|
<p class="section-sub">从网站资源到可分发安装包,只需简单四步。</p>
|
||||||
|
<div class="steps">
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-num">1</div>
|
||||||
|
<h4>导入网站资源</h4>
|
||||||
|
<p>导入 HTML、JS、CSS、图片等文件,自动检测入口文件,保留目录结构。</p>
|
||||||
|
<span class="step-arrow">→</span>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-num">2</div>
|
||||||
|
<h4>配置应用信息</h4>
|
||||||
|
<p>设置名称、图标、版本、窗口尺寸、后端入口等,一切可视化操作。</p>
|
||||||
|
<span class="step-arrow">→</span>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-num">3</div>
|
||||||
|
<h4>一键打包</h4>
|
||||||
|
<p>点击打包,实时查看进度与日志,自动嵌入 Electron 运行时生成安装包。</p>
|
||||||
|
<span class="step-arrow">→</span>
|
||||||
|
</div>
|
||||||
|
<div class="step">
|
||||||
|
<div class="step-num">4</div>
|
||||||
|
<h4>分发与运行</h4>
|
||||||
|
<p>将安装包分发给用户,安装后即可独立运行,无需任何环境配置。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Download -->
|
||||||
|
<section id="download">
|
||||||
|
<div class="container">
|
||||||
|
<span class="section-label">下载安装</span>
|
||||||
|
<h2 class="section-title">选择你的平台</h2>
|
||||||
|
<p class="section-sub">Web2App 支持主流桌面平台,下载对应版本即可开始使用。</p>
|
||||||
|
<div class="platforms">
|
||||||
|
<div class="platform-card">
|
||||||
|
<div class="platform-icon">🪟</div>
|
||||||
|
<h4>Windows</h4>
|
||||||
|
<p class="version">v1.0.0 · x64</p>
|
||||||
|
<a href="../release/win-unpacked/Web2App.exe" class="btn btn-primary" download>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
||||||
|
下载便携版
|
||||||
|
</a>
|
||||||
|
<div style="margin-top:10px;font-size:13px;color:var(--text-muted);">可执行安装包请通过 <code>npm run electron:build</code> 构建</div>
|
||||||
|
</div>
|
||||||
|
<div class="platform-card">
|
||||||
|
<div class="platform-icon">🍎</div>
|
||||||
|
<h4>macOS</h4>
|
||||||
|
<p class="version">v1.0.0 · Intel / Apple Silicon</p>
|
||||||
|
<span class="coming-soon">即将发布</span>
|
||||||
|
</div>
|
||||||
|
<div class="platform-card">
|
||||||
|
<div class="platform-icon">🐧</div>
|
||||||
|
<h4>Linux</h4>
|
||||||
|
<p class="version">v1.0.0 · .AppImage</p>
|
||||||
|
<span class="coming-soon">即将发布</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Architecture -->
|
||||||
|
<section id="architecture">
|
||||||
|
<div class="container">
|
||||||
|
<span class="section-label">技术架构</span>
|
||||||
|
<h2 class="section-title">基于 Electron 构建</h2>
|
||||||
|
<p class="section-sub">Web2App 生成的桌面应用采用分层架构设计,确保性能与可扩展性。</p>
|
||||||
|
<div class="arch-diagram">
|
||||||
|
<div class="arch-box">
|
||||||
|
<div>前端界面(用户网站 HTML / JS / CSS)</div>
|
||||||
|
<div class="arch-sub">
|
||||||
|
<span>Chromium 渲染引擎</span>
|
||||||
|
<span>Vue 3 / React</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="arch-arrow">⬇ HTTP 本地通信 ⬇</div>
|
||||||
|
<div class="arch-box">
|
||||||
|
<div>后端服务</div>
|
||||||
|
<div class="arch-sub">
|
||||||
|
<span>Node.js 运行时</span>
|
||||||
|
<span>Express 路由</span>
|
||||||
|
<span>SQLite 数据库</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="arch-arrow">⬇</div>
|
||||||
|
<div class="arch-box primary">
|
||||||
|
<div>Electron 主进程</div>
|
||||||
|
<div class="arch-sub">
|
||||||
|
<span>窗口管理</span>
|
||||||
|
<span>系统托盘</span>
|
||||||
|
<span>自动启动后端</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="arch-arrow">⬇</div>
|
||||||
|
<div class="arch-box">
|
||||||
|
操作系统 (Windows / macOS / Linux)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<span>© 2026 Web2App. MIT License.</span>
|
||||||
|
<a href="https://github.com/anomalyco/WebpageExer" target="_blank">GitHub 仓库</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user