🔧 Global formatting and update formatting

This commit is contained in:
Tw93
2025-08-05 19:53:58 +08:00
parent 467123068a
commit 7c2c68f3a6
47 changed files with 824 additions and 653 deletions

View File

@@ -1,3 +0,0 @@
{
"Exclude": ["Cargo\\.lock$", "dist", "*\\.md"]
}

2
.gitattributes vendored
View File

@@ -8,4 +8,4 @@ script/* linguist-vendored
/icns2png.py linguist-vendored /icns2png.py linguist-vendored
/rollup.config.js linguist-vendored /rollup.config.js linguist-vendored
src-tauri/src/inject/* linguist-vendored src-tauri/src/inject/* linguist-vendored
src-tauri/src/.pake/* linguist-vendored src-tauri/src/.pake/* linguist-vendored

4
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,2 @@
github: ['tw93'] github: ["tw93"]
custom: ['https://miaoyan.app/cats.html?name=Pake'] custom: ["https://miaoyan.app/cats.html?name=Pake"]

View File

@@ -1,7 +1,7 @@
name: Bug report name: Bug report
description: Problems with the software description: Problems with the software
title: '[Bug] ' title: "[Bug] "
labels: ['bug'] labels: ["bug"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
@@ -73,4 +73,4 @@ body:
- label: I'm willing to submit a PR! - label: I'm willing to submit a PR!
- type: markdown - type: markdown
attributes: attributes:
value: 'Thanks for completing our form!' value: "Thanks for completing our form!"

View File

@@ -1,6 +1,6 @@
name: Feature name: Feature
description: Add new feature, improve code, and more description: Add new feature, improve code, and more
labels: ['enhancement'] labels: ["enhancement"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
@@ -43,4 +43,4 @@ body:
- label: I'm willing to submit a PR! - label: I'm willing to submit a PR!
- type: markdown - type: markdown
attributes: attributes:
value: 'Thanks for completing our form!' value: "Thanks for completing our form!"

77
.github/workflows/code-quality.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
name: Code Quality Check
on:
push:
pull_request:
workflow_dispatch:
permissions:
actions: write
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
formatting:
name: Code Formatting Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Check EditorConfig compliance
uses: editorconfig-checker/action-editorconfig-checker@main
- name: Run EditorConfig checker with exclusions
run: editorconfig-checker -exclude 'Cargo\.lock|dist/.*|.*\.(md|icns|ico|png|jpg|jpeg|gif|svg|desktop|wxs|plist|toml)$|cli\.js$|node_modules/.*|target/.*|src-tauri/(target|icons|png)/.*'
- name: Check Prettier formatting
run: npx prettier --check . --ignore-unknown
rust-quality:
name: Rust Code Quality
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false
defaults:
run:
shell: bash
working-directory: src-tauri
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt, clippy
- uses: rui314/setup-mold@v1
if: matrix.os == 'ubuntu-latest'
- uses: taiki-e/install-action@v1
with:
tool: cargo-hack
- name: Install Ubuntu dependencies
if: matrix.os == 'ubuntu-latest'
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
with:
packages: libdbus-1-dev libsoup3.0-dev libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev gnome-video-effects gnome-video-effects-extra
version: 1.0
- name: Check Rust formatting
run: cargo fmt --all -- --color=always --check
- name: Run Clippy lints
run: cargo hack --feature-powerset --exclude-features cli-build --no-dev-deps clippy

View File

@@ -1,7 +1,7 @@
name: Build and Publish Docker Image name: Build and Publish Docker Image
on: on:
workflow_dispatch: # Manual workflow_dispatch: # Manual
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io

View File

@@ -1,23 +0,0 @@
name: Check EditorConfig
on:
push:
pull_request:
workflow_dispatch:
permissions:
actions: write
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
editorconfig-check:
name: Run EditorConfig Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: editorconfig-checker/action-editorconfig-checker@main
- run: editorconfig-checker -config .ecrc.json

View File

@@ -3,55 +3,55 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
platform: platform:
description: 'Platform' description: "Platform"
required: true required: true
default: 'macos-latest' default: "macos-latest"
type: choice type: choice
options: options:
- 'windows-latest' - "windows-latest"
- 'macos-latest' - "macos-latest"
- 'ubuntu-24.04' - "ubuntu-24.04"
url: url:
description: 'URL' description: "URL"
required: true required: true
name: name:
description: 'Name, English, Linux no capital' description: "Name, English, Linux no capital"
required: true required: true
icon: icon:
description: 'Icon, Image URL, Optional' description: "Icon, Image URL, Optional"
required: false required: false
width: width:
description: 'Width, Optional' description: "Width, Optional"
required: false required: false
default: '1200' default: "1200"
height: height:
description: 'Height, Optional' description: "Height, Optional"
required: false required: false
default: '780' default: "780"
fullscreen: fullscreen:
description: 'Fullscreen, At startup, Optional' description: "Fullscreen, At startup, Optional"
required: false required: false
type: boolean type: boolean
default: false default: false
hide_title_bar: hide_title_bar:
description: 'Hide TitleBar, MacOS only, Optional' description: "Hide TitleBar, MacOS only, Optional"
required: false required: false
type: boolean type: boolean
default: false default: false
multi_arch: multi_arch:
description: 'MultiArch, MacOS only, Optional' description: "MultiArch, MacOS only, Optional"
required: false required: false
type: boolean type: boolean
default: false default: false
targets: targets:
description: 'Targets, Linux only, Optional' description: "Targets, Linux only, Optional"
required: false required: false
default: 'deb' default: "deb"
type: choice type: choice
options: options:
- 'deb' - "deb"
- 'appimage' - "appimage"
- 'rpm' - "rpm"
jobs: jobs:
build: build:

View File

@@ -2,7 +2,7 @@ name: Build All Popular Apps
on: on:
push: push:
tags: tags:
- 'V*' - "V*"
jobs: jobs:
read_apps_config: read_apps_config:

View File

@@ -3,43 +3,43 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
name: name:
description: 'App Name' description: "App Name"
required: true required: true
default: 'twitter' default: "twitter"
title: title:
description: 'App Title' description: "App Title"
required: true required: true
default: 'Twitter' default: "Twitter"
name_zh: name_zh:
description: 'App Name in Chinese' description: "App Name in Chinese"
required: true required: true
default: '推特' default: "推特"
url: url:
description: 'App URL' description: "App URL"
required: true required: true
default: 'https://twitter.com/' default: "https://twitter.com/"
workflow_call: workflow_call:
inputs: inputs:
name: name:
description: 'App Name' description: "App Name"
type: string type: string
required: true required: true
default: 'twitter' default: "twitter"
title: title:
description: 'App Title' description: "App Title"
required: true required: true
type: string type: string
default: 'Twitter' default: "Twitter"
name_zh: name_zh:
description: 'App Name in Chinese' description: "App Name in Chinese"
required: true required: true
type: string type: string
default: '推特' default: "推特"
url: url:
description: 'App URL' description: "App URL"
required: true required: true
type: string type: string
default: 'https://twitter.com/' default: "https://twitter.com/"
jobs: jobs:
build_single_app: build_single_app:
@@ -144,7 +144,7 @@ jobs:
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
if: startsWith(github.ref, 'refs/tags/') != true if: startsWith(github.ref, 'refs/tags/') != true
with: with:
path: 'output/*/*.*' path: "output/*/*.*"
- name: Upload For Release - name: Upload For Release
# arg info: https://github.com/ncipollo/release-action#release-action # arg info: https://github.com/ncipollo/release-action#release-action
@@ -152,5 +152,5 @@ jobs:
if: startsWith(github.ref, 'refs/tags/') == true if: startsWith(github.ref, 'refs/tags/') == true
with: with:
allowUpdates: true allowUpdates: true
artifacts: 'output/*/*.*' artifacts: "output/*/*.*"
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,83 +0,0 @@
name: Check Rust Code
on:
push:
pull_request:
workflow_dispatch:
permissions:
actions: write
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
working-directory: src-tauri
jobs:
cargo-test:
name: Test codebase on ${{ matrix.os }} (cargo test)
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- windows-latest
- ubuntu-latest
- macos-latest
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
- uses: rui314/setup-mold@v1
- uses: taiki-e/install-action@v1
with:
tool: cargo-hack,nextest
- name: Install dependencies for Ubuntu
if: matrix.os == 'ubuntu-latest'
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
with:
packages: libdbus-1-dev libsoup3.0-dev libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev gnome-video-effects gnome-video-effects-extra
version: 1.0
- name: Run unit & integration tests with nextest
run: cargo hack --feature-powerset --exclude-features cli-build nextest run --no-tests=pass
cargo-clippy:
name: Check codebase quality (cargo clippy)
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- windows-latest
- ubuntu-latest
- macos-latest
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy
- uses: taiki-e/install-action@cargo-hack
- name: Install dependencies for Ubuntu
if: matrix.os == 'ubuntu-latest'
uses: awalsh128/cache-apt-pkgs-action@v1.4.3
with:
packages: libdbus-1-dev libsoup3.0-dev libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev build-essential curl wget libssl-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev gnome-video-effects gnome-video-effects-extra
version: 1.0
- name: Run all-features code quality checks
run: cargo hack --feature-powerset --exclude-features cli-build --no-dev-deps clippy
- name: Run normal code quality check
run: cargo clippy
cargo-fmt:
name: Enforce codebase style (cargo fmt)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt
- run: cargo fmt --all -- --color=always --check

View File

@@ -1,3 +1,23 @@
src-tauri/target src-tauri/target
node_modules node_modules
dist/**/* dist/**/*
*.ico
*.icns
*.png
*.jpg
*.jpeg
*.gif
*.svg
*.bin
*.exe
*.dll
*.so
*.dylib
Cargo.lock
src-tauri/Cargo.lock
pnpm-lock.yaml
cli.js
*.desktop
*.wxs
*.plist
*.toml

View File

@@ -1,15 +0,0 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"endOfLine": "lf",
"bracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 140,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"useTabs": false
}

View File

@@ -70,17 +70,17 @@ npm run analyze
1. **CLI Tool** (`bin/`): Node.js/TypeScript-based command-line interface 1. **CLI Tool** (`bin/`): Node.js/TypeScript-based command-line interface
- `bin/cli.ts` - Main CLI entry point with Commander.js - `bin/cli.ts` - Main CLI entry point with Commander.js
- `bin/builders/` - Platform-specific builders (Mac, Windows, Linux) - `bin/builders/` - Platform-specific builders (Mac, Windows, Linux)
- `bin/options/` - CLI option processing and validation - `bin/options/` - CLI option processing and validation
- `bin/utils/` - Utility functions for URL validation, platform detection - `bin/utils/` - Utility functions for URL validation, platform detection
2. **Tauri Application** (`src-tauri/`): Rust-based desktop app framework 2. **Tauri Application** (`src-tauri/`): Rust-based desktop app framework
- `src-tauri/src/lib.rs` - Main application entry point - `src-tauri/src/lib.rs` - Main application entry point
- `src-tauri/src/app/` - Application modules (config, window, system tray, shortcuts) - `src-tauri/src/app/` - Application modules (config, window, system tray, shortcuts)
- `src-tauri/src/inject/` - JavaScript/CSS injection for web pages - `src-tauri/src/inject/` - JavaScript/CSS injection for web pages
- `src-tauri/pake.json` - Default app configuration - `src-tauri/pake.json` - Default app configuration
3. **Build System**: Uses Rollup for CLI bundling and Tauri for app packaging 3. **Build System**: Uses Rollup for CLI bundling and Tauri for app packaging

View File

@@ -20,21 +20,17 @@ community include:
- Demonstrating empathy and kindness toward other people - Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences - Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback - Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
and learning from the experience - Focusing on what is best not just for us as individuals, but for the overall community
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include: Examples of unacceptable behavior include:
- The use of erotic language or imagery, and sexual attention or - The use of erotic language or imagery, and sexual attention or advances of any kind
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks - Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment - Public or private harassment
- Publishing others' private information, such as a physical or email - Publishing others' private information, such as a physical or email
address, without their explicit permission address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a - Other conduct which could reasonably be considered inappropriate in a professional setting
professional setting
## Enforcement Responsibilities ## Enforcement Responsibilities

View File

@@ -47,7 +47,7 @@
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/WeRead.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/WeRead.jpg width=600/></td>
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/Twitter.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/Twitter.jpg width=600/></td>
</tr> </tr>
<tr> <tr>
<td>Grok <td>Grok
<a href="https://github.com/tw93/Pake/releases/latest/download/Grok.dmg">Mac</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Grok.dmg">Mac</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Grok_x64.msi">Windows</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Grok_x64.msi">Windows</a>
@@ -112,7 +112,7 @@
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/ProgramMusic.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/ProgramMusic.jpg width=600/></td>
</tr> </tr>
<tr> <tr>
<td>Excalidraw <td>Excalidraw
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw.dmg">Mac</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw.dmg">Mac</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x64.msi">Windows</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x64.msi">Windows</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x86_64.deb">Linux</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x86_64.deb">Linux</a>

View File

@@ -46,7 +46,7 @@
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/WeRead.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/WeRead.jpg width=600/></td>
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/Twitter.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/Twitter.jpg width=600/></td>
</tr> </tr>
<tr> <tr>
<td>Grok <td>Grok
<a href="https://github.com/tw93/Pake/releases/latest/download/Grok.dmg">Mac</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Grok.dmg">Mac</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Grok_x64.msi">Windows</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Grok_x64.msi">Windows</a>
@@ -111,7 +111,7 @@
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/ProgramMusic.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/ProgramMusic.jpg width=600/></td>
</tr> </tr>
<tr> <tr>
<td>Excalidraw <td>Excalidraw
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw.dmg">Mac</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw.dmg">Mac</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x64.msi">Windows</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x64.msi">Windows</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x86_64.deb">Linux</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x86_64.deb">Linux</a>

View File

@@ -47,7 +47,7 @@
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/WeRead.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/WeRead.jpg width=600/></td>
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/Twitter.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/Twitter.jpg width=600/></td>
</tr> </tr>
<tr> <tr>
<td>Grok <td>Grok
<a href="https://github.com/tw93/Pake/releases/latest/download/Grok.dmg">Mac</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Grok.dmg">Mac</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Grok_x64.msi">Windows</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Grok_x64.msi">Windows</a>
@@ -112,7 +112,7 @@
<td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/ProgramMusic.jpg width=600/></td> <td><img src=https://raw.githubusercontent.com/tw93/static/main/pake/ProgramMusic.jpg width=600/></td>
</tr> </tr>
<tr> <tr>
<td>Excalidraw <td>Excalidraw
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw.dmg">Mac</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw.dmg">Mac</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x64.msi">Windows</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x64.msi">Windows</a>
<a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x86_64.deb">Linux</a> <a href="https://github.com/tw93/Pake/releases/latest/download/Excalidraw_x86_64.deb">Linux</a>

7
bin/README.md vendored
View File

@@ -13,7 +13,6 @@ npm install pake-cli -g
- **CRITICAL**: Consult [Tauri prerequisites](https://tauri.app/start/prerequisites/) before proceeding. - **CRITICAL**: Consult [Tauri prerequisites](https://tauri.app/start/prerequisites/) before proceeding.
- For Windows users (ensure that `Win10 SDK (10.0.19041.0)` and `Visual Studio build tool 2022 (>=17.2)` are installed), additional installations are required: - For Windows users (ensure that `Win10 SDK (10.0.19041.0)` and `Visual Studio build tool 2022 (>=17.2)` are installed), additional installations are required:
1. Microsoft Visual C++ 2015-2022 Redistributable (x64) 1. Microsoft Visual C++ 2015-2022 Redistributable (x64)
2. Microsoft Visual C++ 2015-2022 Redistributable (x86) 2. Microsoft Visual C++ 2015-2022 Redistributable (x86)
3. Microsoft Visual C++ 2012 Redistributable (x86) (optional) 3. Microsoft Visual C++ 2012 Redistributable (x86) (optional)
@@ -251,7 +250,7 @@ Supports both comma-separated and multiple option formats:
# Comma-separated (recommended) # Comma-separated (recommended)
--inject ./tools/style.css,./tools/hotkey.js --inject ./tools/style.css,./tools/hotkey.js
# Multiple options # Multiple options
--inject ./tools/style.css --inject ./tools/hotkey.js --inject ./tools/style.css --inject ./tools/hotkey.js
# Single file # Single file
@@ -285,8 +284,8 @@ The `DEFAULT_DEV_PAKE_OPTIONS` configuration in `bin/defaults.ts` can be modifie
```typescript ```typescript
export const DEFAULT_DEV_PAKE_OPTIONS: PakeCliOptions & { url: string } = { export const DEFAULT_DEV_PAKE_OPTIONS: PakeCliOptions & { url: string } = {
...DEFAULT_PAKE_OPTIONS, ...DEFAULT_PAKE_OPTIONS,
url: 'https://weread.qq.com', url: "https://weread.qq.com",
name: 'Weread', name: "Weread",
}; };
``` ```

5
bin/README_CN.md vendored
View File

@@ -13,7 +13,6 @@ npm install pake-cli -g
- **非常重要**:请参阅 Tauri 的 [依赖项指南](https://tauri.app/start/prerequisites/)。 - **非常重要**:请参阅 Tauri 的 [依赖项指南](https://tauri.app/start/prerequisites/)。
- 对于 Windows 用户,请确保至少安装了 `Win10 SDK(10.0.19041.0)``Visual Studio Build Tools 2022版本 17.2 或更高)`,此外还需要安装以下组件: - 对于 Windows 用户,请确保至少安装了 `Win10 SDK(10.0.19041.0)``Visual Studio Build Tools 2022版本 17.2 或更高)`,此外还需要安装以下组件:
1. Microsoft Visual C++ 2015-2022 Redistributable (x64) 1. Microsoft Visual C++ 2015-2022 Redistributable (x64)
2. Microsoft Visual C++ 2015-2022 Redistributable (x86) 2. Microsoft Visual C++ 2015-2022 Redistributable (x86)
3. Microsoft Visual C++ 2012 Redistributable (x86)(可选) 3. Microsoft Visual C++ 2012 Redistributable (x86)(可选)
@@ -287,8 +286,8 @@ pake [url] [options]
```typescript ```typescript
export const DEFAULT_DEV_PAKE_OPTIONS: PakeCliOptions & { url: string } = { export const DEFAULT_DEV_PAKE_OPTIONS: PakeCliOptions & { url: string } = {
...DEFAULT_PAKE_OPTIONS, ...DEFAULT_PAKE_OPTIONS,
url: 'https://weread.qq.com', url: "https://weread.qq.com",
name: 'Weread', name: "Weread",
}; };
``` ```

View File

@@ -56,13 +56,17 @@ export default abstract class BaseBuilder {
logger.info('✺ Located in China, using npm/rsProxy CN mirror.'); logger.info('✺ Located in China, using npm/rsProxy CN mirror.');
const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml'); const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
await fsExtra.copy(projectCnConf, projectConf); await fsExtra.copy(projectCnConf, projectConf);
await shellExec(`cd "${npmDirectory}" && npm install --registry=https://registry.npmmirror.com`); await shellExec(
`cd "${npmDirectory}" && npm install --registry=https://registry.npmmirror.com`,
);
} else { } else {
await shellExec(`cd "${npmDirectory}" && npm install`); await shellExec(`cd "${npmDirectory}" && npm install`);
} }
spinner.succeed(chalk.green('Package installed!')); spinner.succeed(chalk.green('Package installed!'));
if (!tauriTargetPathExists) { if (!tauriTargetPathExists) {
logger.warn('✼ The first packaging may be slow, please be patient and wait, it will be faster afterwards.'); logger.warn(
'✼ The first packaging may be slow, please be patient and wait, it will be faster afterwards.',
);
} }
} }
@@ -110,7 +114,16 @@ export default abstract class BaseBuilder {
return `src-tauri/target/${basePath}/bundle/`; return `src-tauri/target/${basePath}/bundle/`;
} }
protected getBuildAppPath(npmDirectory: string, fileName: string, fileType: string): string { protected getBuildAppPath(
return path.join(npmDirectory, this.getBasePath(), fileType.toLowerCase(), `${fileName}.${fileType}`); npmDirectory: string,
fileName: string,
fileType: string,
): string {
return path.join(
npmDirectory,
this.getBasePath(),
fileType.toLowerCase(),
`${fileName}.${fileType}`,
);
} }
} }

View File

@@ -6,7 +6,10 @@ import { PakeAppOptions } from '@/types';
const { platform } = process; const { platform } = process;
const buildersMap: Record<string, new (options: PakeAppOptions) => BaseBuilder> = { const buildersMap: Record<
string,
new (options: PakeAppOptions) => BaseBuilder
> = {
darwin: MacBuilder, darwin: MacBuilder,
win32: WinBuilder, win32: WinBuilder,
linux: LinuxBuilder, linux: LinuxBuilder,

View File

@@ -20,7 +20,9 @@ export default class MacBuilder extends BaseBuilder {
} }
protected getBuildCommand(): string { protected getBuildCommand(): string {
return this.options.multiArch ? 'npm run build:mac' : super.getBuildCommand(); return this.options.multiArch
? 'npm run build:mac'
: super.getBuildCommand();
} }
protected getBasePath(): string { protected getBasePath(): string {

125
bin/cli.ts vendored
View File

@@ -3,7 +3,10 @@ import { program, Option } from 'commander';
import log from 'loglevel'; import log from 'loglevel';
import packageJson from '../package.json'; import packageJson from '../package.json';
import BuilderProvider from './builders/BuilderProvider'; import BuilderProvider from './builders/BuilderProvider';
import { DEFAULT_PAKE_OPTIONS as DEFAULT, DEFAULT_PAKE_OPTIONS } from './defaults'; import {
DEFAULT_PAKE_OPTIONS as DEFAULT,
DEFAULT_PAKE_OPTIONS,
} from './defaults';
import { checkUpdateTips } from './helpers/updater'; import { checkUpdateTips } from './helpers/updater';
import handleInputOptions from './options/index'; import handleInputOptions from './options/index';
@@ -18,7 +21,10 @@ ${green('| __/ (_| | < __/')} ${yellow('https://github.com/tw93/pake')}
${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with Rust.')} ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with Rust.')}
`; `;
program.addHelpText('beforeAll', logo).usage(`[url] [options]`).showHelpAfterError(); program
.addHelpText('beforeAll', logo)
.usage(`[url] [options]`)
.showHelpAfterError();
program program
.argument('[url]', 'The web URL you want to package', validateUrlInput) .argument('[url]', 'The web URL you want to package', validateUrlInput)
@@ -26,15 +32,26 @@ program
// If the platform is Linux, use `-` as the connector, and convert all characters to lowercase. // If the platform is Linux, use `-` as the connector, and convert all characters to lowercase.
// For example, Google Translate will become google-translate. // For example, Google Translate will become google-translate.
.option('--name <string...>', 'Application name', (value, previous) => { .option('--name <string...>', 'Application name', (value, previous) => {
const platform = process.platform const platform = process.platform;
const connector = platform === 'linux' ? '-' : ' ' const connector = platform === 'linux' ? '-' : ' ';
const name = previous === undefined ? value : `${previous}${connector}${value}` const name =
previous === undefined ? value : `${previous}${connector}${value}`;
return platform === 'linux' ? name.toLowerCase() : name
return platform === 'linux' ? name.toLowerCase() : name;
}) })
.option('--icon <string>', 'Application icon', DEFAULT.icon) .option('--icon <string>', 'Application icon', DEFAULT.icon)
.option('--width <number>', 'Window width', validateNumberInput, DEFAULT.width) .option(
.option('--height <number>', 'Window height', validateNumberInput, DEFAULT.height) '--width <number>',
'Window width',
validateNumberInput,
DEFAULT.width,
)
.option(
'--height <number>',
'Window height',
validateNumberInput,
DEFAULT.height,
)
.option('--use-local-file', 'Use local file packaging', DEFAULT.useLocalFile) .option('--use-local-file', 'Use local file packaging', DEFAULT.useLocalFile)
.option('--fullscreen', 'Start in full screen', DEFAULT.fullscreen) .option('--fullscreen', 'Start in full screen', DEFAULT.fullscreen)
.option('--hide-title-bar', 'For Mac, hide title bar', DEFAULT.hideTitleBar) .option('--hide-title-bar', 'For Mac, hide title bar', DEFAULT.hideTitleBar)
@@ -44,41 +61,93 @@ program
'Injection of .js or .css files', 'Injection of .js or .css files',
(val, previous) => { (val, previous) => {
if (!val) return DEFAULT.inject; if (!val) return DEFAULT.inject;
// Split by comma and trim whitespace, filter out empty strings // Split by comma and trim whitespace, filter out empty strings
const files = val.split(',') const files = val
.map(item => item.trim()) .split(',')
.filter(item => item.length > 0); .map((item) => item.trim())
.filter((item) => item.length > 0);
// If previous values exist (from multiple --inject options), merge them // If previous values exist (from multiple --inject options), merge them
return previous ? [...previous, ...files] : files; return previous ? [...previous, ...files] : files;
}, },
DEFAULT.inject, DEFAULT.inject,
) )
.option('--debug', 'Debug build and more output', DEFAULT.debug) .option('--debug', 'Debug build and more output', DEFAULT.debug)
.addOption(new Option('--proxy-url <url>', 'Proxy URL for all network requests').default(DEFAULT_PAKE_OPTIONS.proxyUrl).hideHelp())
.addOption(new Option('--user-agent <string>', 'Custom user agent').default(DEFAULT.userAgent).hideHelp())
.addOption(new Option('--targets <string>', 'For Linux, option "deb" or "appimage"').default(DEFAULT.targets).hideHelp())
.addOption(new Option('--app-version <string>', 'App version, the same as package.json version').default(DEFAULT.appVersion).hideHelp())
.addOption(new Option('--always-on-top', 'Always on the top level').default(DEFAULT.alwaysOnTop).hideHelp())
.addOption(new Option('--dark-mode', 'Force Mac app to use dark mode').default(DEFAULT.darkMode).hideHelp())
.addOption(new Option('--disabled-web-shortcuts', 'Disabled webPage shortcuts').default(DEFAULT.disabledWebShortcuts).hideHelp())
.addOption( .addOption(
new Option('--activation-shortcut <string>', 'Shortcut key to active App').default(DEFAULT_PAKE_OPTIONS.activationShortcut).hideHelp(), new Option('--proxy-url <url>', 'Proxy URL for all network requests')
.default(DEFAULT_PAKE_OPTIONS.proxyUrl)
.hideHelp(),
)
.addOption(
new Option('--user-agent <string>', 'Custom user agent')
.default(DEFAULT.userAgent)
.hideHelp(),
)
.addOption(
new Option('--targets <string>', 'For Linux, option "deb" or "appimage"')
.default(DEFAULT.targets)
.hideHelp(),
)
.addOption(
new Option(
'--app-version <string>',
'App version, the same as package.json version',
)
.default(DEFAULT.appVersion)
.hideHelp(),
)
.addOption(
new Option('--always-on-top', 'Always on the top level')
.default(DEFAULT.alwaysOnTop)
.hideHelp(),
)
.addOption(
new Option('--dark-mode', 'Force Mac app to use dark mode')
.default(DEFAULT.darkMode)
.hideHelp(),
)
.addOption(
new Option('--disabled-web-shortcuts', 'Disabled webPage shortcuts')
.default(DEFAULT.disabledWebShortcuts)
.hideHelp(),
)
.addOption(
new Option('--activation-shortcut <string>', 'Shortcut key to active App')
.default(DEFAULT_PAKE_OPTIONS.activationShortcut)
.hideHelp(),
)
.addOption(
new Option('--show-system-tray', 'Show system tray in app')
.default(DEFAULT.showSystemTray)
.hideHelp(),
)
.addOption(
new Option('--system-tray-icon <string>', 'Custom system tray icon')
.default(DEFAULT.systemTrayIcon)
.hideHelp(),
)
.addOption(
new Option('--hide-on-close', 'Hide window on close instead of exiting')
.default(DEFAULT.hideOnClose)
.hideHelp(),
)
.addOption(
new Option('--installer-language <string>', 'Installer language')
.default(DEFAULT.installerLanguage)
.hideHelp(),
) )
.addOption(new Option('--show-system-tray', 'Show system tray in app').default(DEFAULT.showSystemTray).hideHelp())
.addOption(new Option('--system-tray-icon <string>', 'Custom system tray icon').default(DEFAULT.systemTrayIcon).hideHelp())
.addOption(new Option('--hide-on-close', 'Hide window on close instead of exiting').default(DEFAULT.hideOnClose).hideHelp())
.addOption(new Option('--installer-language <string>', 'Installer language').default(DEFAULT.installerLanguage).hideHelp())
.version(packageJson.version, '-v, --version', 'Output the current version') .version(packageJson.version, '-v, --version', 'Output the current version')
.action(async (url: string, options: PakeCliOptions) => { .action(async (url: string, options: PakeCliOptions) => {
await checkUpdateTips(); await checkUpdateTips();
if (!url) { if (!url) {
program.outputHelp(str => { program.outputHelp((str) => {
return str return str
.split('\n') .split('\n')
.filter(line => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line)) .filter(
(line) => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line),
)
.join('\n'); .join('\n');
}); });
process.exit(0); process.exit(0);

2
bin/defaults.ts vendored
View File

@@ -18,7 +18,7 @@ export const DEFAULT_PAKE_OPTIONS: PakeCliOptions = {
targets: 'deb', targets: 'deb',
useLocalFile: false, useLocalFile: false,
systemTrayIcon: '', systemTrayIcon: '',
proxyUrl: "", proxyUrl: '',
debug: false, debug: false,
inject: [], inject: [],
installerLanguage: 'en-US', installerLanguage: 'en-US',

5
bin/dev.ts vendored
View File

@@ -6,7 +6,10 @@ import BuilderProvider from './builders/BuilderProvider';
async function startBuild() { async function startBuild() {
log.setDefaultLevel('debug'); log.setDefaultLevel('debug');
const appOptions = await handleInputOptions(DEFAULT_DEV_PAKE_OPTIONS, DEFAULT_DEV_PAKE_OPTIONS.url); const appOptions = await handleInputOptions(
DEFAULT_DEV_PAKE_OPTIONS,
DEFAULT_DEV_PAKE_OPTIONS.url,
);
log.debug('PakeAppOptions', appOptions); log.debug('PakeAppOptions', appOptions);
const builder = BuilderProvider.create(appOptions); const builder = BuilderProvider.create(appOptions);

50
bin/helpers/merge.ts vendored
View File

@@ -7,7 +7,11 @@ import logger from '@/options/logger';
import { PakeAppOptions, PlatformMap } from '@/types'; import { PakeAppOptions, PlatformMap } from '@/types';
import { tauriConfigDirectory } from '@/utils/dir'; import { tauriConfigDirectory } from '@/utils/dir';
export async function mergeConfig(url: string, options: PakeAppOptions, tauriConf: any) { export async function mergeConfig(
url: string,
options: PakeAppOptions,
tauriConf: any,
) {
const { const {
width, width,
height, height,
@@ -78,7 +82,11 @@ export async function mergeConfig(url: string, options: PakeAppOptions, tauriCon
// ignore it, because about_pake.html have be erased. // ignore it, because about_pake.html have be erased.
// const filesToCopyBack = ['cli.js', 'about_pake.html']; // const filesToCopyBack = ['cli.js', 'about_pake.html'];
const filesToCopyBack = ['cli.js']; const filesToCopyBack = ['cli.js'];
await Promise.all(filesToCopyBack.map(file => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file)))); await Promise.all(
filesToCopyBack.map((file) =>
fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file)),
),
);
} }
tauriConf.pake.windows[0].url = fileName; tauriConf.pake.windows[0].url = fileName;
@@ -107,7 +115,9 @@ export async function mergeConfig(url: string, options: PakeAppOptions, tauriCon
if (validTargets.includes(options.targets)) { if (validTargets.includes(options.targets)) {
tauriConf.bundle.targets = [options.targets]; tauriConf.bundle.targets = [options.targets];
} else { } else {
logger.warn(`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`); logger.warn(
`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`,
);
} }
} }
@@ -154,23 +164,31 @@ export async function mergeConfig(url: string, options: PakeAppOptions, tauriCon
logger.warn(`✼ Icon will remain as default.`); logger.warn(`✼ Icon will remain as default.`);
} }
} else { } else {
logger.warn('✼ Custom icon path may be invalid, default icon will be used instead.'); logger.warn(
'✼ Custom icon path may be invalid, default icon will be used instead.',
);
tauriConf.bundle.icon = [iconInfo.defaultIcon]; tauriConf.bundle.icon = [iconInfo.defaultIcon];
} }
// Set tray icon path. // Set tray icon path.
let trayIconPath = platform === 'darwin' ? 'png/icon_512.png' : tauriConf.bundle.icon[0]; let trayIconPath =
platform === 'darwin' ? 'png/icon_512.png' : tauriConf.bundle.icon[0];
if (systemTrayIcon.length > 0) { if (systemTrayIcon.length > 0) {
try { try {
await fsExtra.pathExists(systemTrayIcon); await fsExtra.pathExists(systemTrayIcon);
// 需要判断图标格式默认只支持ico和png两种 // 需要判断图标格式默认只支持ico和png两种
let iconExt = path.extname(systemTrayIcon).toLowerCase(); let iconExt = path.extname(systemTrayIcon).toLowerCase();
if (iconExt == '.png' || iconExt == '.ico') { if (iconExt == '.png' || iconExt == '.ico') {
const trayIcoPath = path.join(npmDirectory, `src-tauri/png/${name.toLowerCase()}${iconExt}`); const trayIcoPath = path.join(
npmDirectory,
`src-tauri/png/${name.toLowerCase()}${iconExt}`,
);
trayIconPath = `png/${name.toLowerCase()}${iconExt}`; trayIconPath = `png/${name.toLowerCase()}${iconExt}`;
await fsExtra.copy(systemTrayIcon, trayIcoPath); await fsExtra.copy(systemTrayIcon, trayIcoPath);
} else { } else {
logger.warn(`✼ System tray icon must be .ico or .png, but you provided ${iconExt}.`); logger.warn(
`✼ System tray icon must be .ico or .png, but you provided ${iconExt}.`,
);
logger.warn(`✼ Default system tray icon will be used.`); logger.warn(`✼ Default system tray icon will be used.`);
} }
} catch { } catch {
@@ -184,15 +202,22 @@ export async function mergeConfig(url: string, options: PakeAppOptions, tauriCon
delete tauriConf.app.trayIcon; delete tauriConf.app.trayIcon;
const injectFilePath = path.join(npmDirectory, `src-tauri/src/inject/custom.js`); const injectFilePath = path.join(
npmDirectory,
`src-tauri/src/inject/custom.js`,
);
// inject js or css files // inject js or css files
if (inject?.length > 0) { if (inject?.length > 0) {
if (!inject.every(item => item.endsWith('.css') || item.endsWith('.js'))) { if (
!inject.every((item) => item.endsWith('.css') || item.endsWith('.js'))
) {
logger.error('The injected file must be in either CSS or JS format.'); logger.error('The injected file must be in either CSS or JS format.');
return; return;
} }
const files = inject.map(filepath => (path.isAbsolute(filepath) ? filepath : path.join(process.cwd(), filepath))); const files = inject.map((filepath) =>
path.isAbsolute(filepath) ? filepath : path.join(process.cwd(), filepath),
);
tauriConf.pake.inject = files; tauriConf.pake.inject = files;
await combineFiles(files, injectFilePath); await combineFiles(files, injectFilePath);
} else { } else {
@@ -208,7 +233,10 @@ export async function mergeConfig(url: string, options: PakeAppOptions, tauriCon
linux: 'tauri.linux.conf.json', linux: 'tauri.linux.conf.json',
}; };
const configPath = path.join(tauriConfigDirectory, platformConfigPaths[platform]); const configPath = path.join(
tauriConfigDirectory,
platformConfigPaths[platform],
);
const bundleConf = { bundle: tauriConf.bundle }; const bundleConf = { bundle: tauriConf.bundle };
console.log('pakeConfig', tauriConf.pake); console.log('pakeConfig', tauriConf.pake);

4
bin/helpers/rust.ts vendored
View File

@@ -18,7 +18,9 @@ export async function installRust() {
const spinner = getSpinner('Downloading Rust...'); const spinner = getSpinner('Downloading Rust...');
try { try {
await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac); await shellExec(
IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac,
);
spinner.succeed(chalk.green('Rust installed successfully!')); spinner.succeed(chalk.green('Rust installed successfully!'));
} catch (error) { } catch (error) {
console.error('Error installing Rust:', error.message); console.error('Error installing Rust:', error.message);

View File

@@ -2,5 +2,7 @@ import updateNotifier from 'update-notifier';
import packageJson from '../../package.json'; import packageJson from '../../package.json';
export async function checkUpdateTips() { export async function checkUpdateTips() {
updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({ isGlobal: true }); updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({
isGlobal: true,
});
} }

17
bin/options/icon.ts vendored
View File

@@ -19,12 +19,14 @@ export async function handleIcon(options: PakeAppOptions) {
return path.resolve(options.icon); return path.resolve(options.icon);
} }
} else { } else {
logger.warn('✼ No icon given, default in use. For a custom icon, use --icon option.'); logger.warn(
'✼ No icon given, default in use. For a custom icon, use --icon option.',
);
const iconPath = IS_WIN const iconPath = IS_WIN
? 'src-tauri/png/icon_256.ico' ? 'src-tauri/png/icon_256.ico'
: IS_LINUX : IS_LINUX
? 'src-tauri/png/icon_512.png' ? 'src-tauri/png/icon_512.png'
: 'src-tauri/icons/icon.icns'; : 'src-tauri/icons/icon.icns';
return path.join(npmDirectory, iconPath); return path.join(npmDirectory, iconPath);
} }
} }
@@ -32,7 +34,9 @@ export async function handleIcon(options: PakeAppOptions) {
export async function downloadIcon(iconUrl: string) { export async function downloadIcon(iconUrl: string) {
const spinner = getSpinner('Downloading icon...'); const spinner = getSpinner('Downloading icon...');
try { try {
const iconResponse = await axios.get(iconUrl, { responseType: 'arraybuffer' }); const iconResponse = await axios.get(iconUrl, {
responseType: 'arraybuffer',
});
const iconData = await iconResponse.data; const iconData = await iconResponse.data;
if (!iconData) { if (!iconData) {
@@ -49,7 +53,10 @@ export async function downloadIcon(iconUrl: string) {
// Fix this for linux // Fix this for linux
if (IS_LINUX) { if (IS_LINUX) {
iconPath = 'png/linux_temp.png'; iconPath = 'png/linux_temp.png';
await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, iconData); await fsExtra.outputFile(
`${npmDirectory}/src-tauri/${iconPath}`,
iconData,
);
} else { } else {
await fsExtra.outputFile(iconPath, iconData); await fsExtra.outputFile(iconPath, iconData);
} }

View File

@@ -20,7 +20,10 @@ function isValidName(name: string, platform: NodeJS.Platform): boolean {
return !!name && reg.test(name); return !!name && reg.test(name);
} }
export default async function handleOptions(options: PakeCliOptions, url: string): Promise<PakeAppOptions> { export default async function handleOptions(
options: PakeCliOptions,
url: string,
): Promise<PakeAppOptions> {
const { platform } = process; const { platform } = process;
const isActions = process.env.GITHUB_ACTIONS; const isActions = process.env.GITHUB_ACTIONS;
let name = options.name; let name = options.name;
@@ -36,7 +39,8 @@ export default async function handleOptions(options: PakeCliOptions, url: string
if (!isValidName(name, platform)) { if (!isValidName(name, platform)) {
const LINUX_NAME_ERROR = `✕ Name should only include lowercase letters, numbers, and dashes (not leading dashes), and must contain at least one lowercase letter or number. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`; const LINUX_NAME_ERROR = `✕ Name should only include lowercase letters, numbers, and dashes (not leading dashes), and must contain at least one lowercase letter or number. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`;
const DEFAULT_NAME_ERROR = `✕ Name should only include letters, numbers, dashes, and spaces (not leading dashes and spaces), and must contain at least one letter or number. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead, we-read, We Read.`; const DEFAULT_NAME_ERROR = `✕ Name should only include letters, numbers, dashes, and spaces (not leading dashes and spaces), and must contain at least one letter or number. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead, we-read, We Read.`;
const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR; const errorMsg =
platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR;
logger.error(errorMsg); logger.error(errorMsg);
if (isActions) { if (isActions) {
name = resolveAppName(url, platform); name = resolveAppName(url, platform);

View File

@@ -3,19 +3,19 @@ import log from 'loglevel';
const logger = { const logger = {
info(...msg: any[]) { info(...msg: any[]) {
log.info(...msg.map(m => chalk.white(m))); log.info(...msg.map((m) => chalk.white(m)));
}, },
debug(...msg: any[]) { debug(...msg: any[]) {
log.debug(...msg); log.debug(...msg);
}, },
error(...msg: any[]) { error(...msg: any[]) {
log.error(...msg.map(m => chalk.red(m))); log.error(...msg.map((m) => chalk.red(m)));
}, },
warn(...msg: any[]) { warn(...msg: any[]) {
log.info(...msg.map(m => chalk.yellow(m))); log.info(...msg.map((m) => chalk.yellow(m)));
}, },
success(...msg: any[]) { success(...msg: any[]) {
log.info(...msg.map(m => chalk.green(m))); log.info(...msg.map((m) => chalk.green(m)));
}, },
}; };

View File

@@ -1,7 +1,7 @@
import fs from 'fs'; import fs from 'fs';
export default async function combineFiles(files: string[], output: string) { export default async function combineFiles(files: string[], output: string) {
const contents = files.map(file => { const contents = files.map((file) => {
const fileContent = fs.readFileSync(file); const fileContent = fs.readFileSync(file);
if (file.endsWith('.css')) { if (file.endsWith('.css')) {
return ( return (
@@ -11,7 +11,11 @@ export default async function combineFiles(files: string[], output: string) {
); );
} }
return "window.addEventListener('DOMContentLoaded', (_event) => { " + fileContent + ' });'; return (
"window.addEventListener('DOMContentLoaded', (_event) => { " +
fileContent +
' });'
);
}); });
fs.writeFileSync(output, contents.join('\n')); fs.writeFileSync(output, contents.join('\n'));
return files; return files;

11
bin/utils/info.ts vendored
View File

@@ -5,11 +5,18 @@ import chalk from 'chalk';
// Generates an identifier based on the given URL. // Generates an identifier based on the given URL.
export function getIdentifier(url: string) { export function getIdentifier(url: string) {
const postFixHash = crypto.createHash('md5').update(url).digest('hex').substring(0, 6); const postFixHash = crypto
.createHash('md5')
.update(url)
.digest('hex')
.substring(0, 6);
return `com.pake.${postFixHash}`; return `com.pake.${postFixHash}`;
} }
export async function promptText(message: string, initial?: string): Promise<string> { export async function promptText(
message: string,
initial?: string,
): Promise<string> {
const response = await prompts({ const response = await prompts({
type: 'text', type: 'text',
name: 'content', name: 'content',

4
bin/utils/ip.ts vendored
View File

@@ -13,13 +13,13 @@ const ping = async (host: string) => {
// Prevent timeouts from affecting user experience. // Prevent timeouts from affecting user experience.
const requestPromise = new Promise<number>((resolve, reject) => { const requestPromise = new Promise<number>((resolve, reject) => {
const req = http.get(`http://${ip.address}`, res => { const req = http.get(`http://${ip.address}`, (res) => {
const delay = new Date().getTime() - start.getTime(); const delay = new Date().getTime() - start.getTime();
res.resume(); res.resume();
resolve(delay); resolve(delay);
}); });
req.on('error', err => { req.on('error', (err) => {
reject(err); reject(err);
}); });
}); });

6
bin/utils/shell.ts vendored
View File

@@ -5,10 +5,12 @@ export async function shellExec(command: string) {
try { try {
const { exitCode } = await execa(command, { const { exitCode } = await execa(command, {
cwd: npmDirectory, cwd: npmDirectory,
stdio: 'inherit' stdio: 'inherit',
}); });
return exitCode; return exitCode;
} catch (error) { } catch (error) {
throw new Error(`Error occurred while executing command "${command}". Exit code: ${error.exitCode}`); throw new Error(
`Error occurred while executing command "${command}". Exit code: ${error.exitCode}`,
);
} }
} }

332
dist/cli.js vendored
View File

@@ -23,232 +23,232 @@ var name = "pake-cli";
var version$1 = "3.1.2"; var version$1 = "3.1.2";
var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。"; var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。";
var engines = { var engines = {
node: ">=16.0.0" node: ">=16.0.0"
}; };
var bin = { var bin = {
pake: "./cli.js" pake: "./cli.js"
}; };
var repository = { var repository = {
type: "git", type: "git",
url: "https://github.com/tw93/pake.git" url: "https://github.com/tw93/pake.git"
}; };
var author = { var author = {
name: "Tw93", name: "Tw93",
email: "tw93@qq.com" email: "tw93@qq.com"
}; };
var keywords = [ var keywords = [
"pake", "pake",
"pake-cli", "pake-cli",
"rust", "rust",
"tauri", "tauri",
"no-electron", "no-electron",
"productivity" "productivity"
]; ];
var files = [ var files = [
"dist", "dist",
"src-tauri", "src-tauri",
"cli.js" "cli.js"
]; ];
var scripts = { var scripts = {
start: "npm run dev", start: "npm run dev",
dev: "npm run tauri dev", dev: "npm run tauri dev",
build: "npm run tauri build --release", build: "npm run tauri build --release",
"build:debug": "npm run tauri build -- --debug", "build:debug": "npm run tauri build -- --debug",
"build:mac": "npm run tauri build -- --target universal-apple-darwin", "build:mac": "npm run tauri build -- --target universal-apple-darwin",
"build:config": "chmod +x script/app_config.mjs && node script/app_config.mjs", "build:config": "chmod +x script/app_config.mjs && node script/app_config.mjs",
analyze: "cd src-tauri && cargo bloat --release --crates", analyze: "cd src-tauri && cargo bloat --release --crates",
tauri: "tauri", tauri: "tauri",
cli: "rollup -c rollup.config.js --watch", cli: "rollup -c rollup.config.js --watch",
"cli:dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -w", "cli:dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -w",
"cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js", "cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js",
prepublishOnly: "npm run cli:build" prepublishOnly: "npm run cli:build"
}; };
var type = "module"; var type = "module";
var exports = "./dist/pake.js"; var exports = "./dist/pake.js";
var license = "MIT"; var license = "MIT";
var dependencies = { var dependencies = {
"@tauri-apps/api": "^2.2.0", "@tauri-apps/api": "^2.2.0",
"@tauri-apps/cli": "^2.2.5", "@tauri-apps/cli": "^2.2.5",
axios: "^1.7.9", axios: "^1.7.9",
chalk: "^5.4.1", chalk: "^5.4.1",
commander: "^13.1.0", commander: "^13.1.0",
execa: "^9.5.2", execa: "^9.5.2",
"file-type": "^20.0.0", "file-type": "^20.0.0",
"fs-extra": "^11.3.0", "fs-extra": "^11.3.0",
"is-url": "^1.2.4", "is-url": "^1.2.4",
loglevel: "^1.9.2", loglevel: "^1.9.2",
ora: "^8.1.1", ora: "^8.1.1",
prompts: "^2.4.2", prompts: "^2.4.2",
psl: "^1.15.0", psl: "^1.15.0",
"tmp-promise": "^3.0.3", "tmp-promise": "^3.0.3",
"update-notifier": "^7.3.1" "update-notifier": "^7.3.1"
}; };
var devDependencies = { var devDependencies = {
"@rollup/plugin-alias": "^5.1.1", "@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-commonjs": "^28.0.2", "@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-json": "^6.1.0", "@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-replace": "^6.0.2", "@rollup/plugin-replace": "^6.0.2",
"@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-terser": "^0.4.4",
"@types/fs-extra": "^11.0.4", "@types/fs-extra": "^11.0.4",
"@types/is-url": "^1.2.32", "@types/is-url": "^1.2.32",
"@types/node": "^22.10.8", "@types/node": "^22.10.8",
"@types/page-icon": "^0.3.6", "@types/page-icon": "^0.3.6",
"@types/prompts": "^2.4.9", "@types/prompts": "^2.4.9",
"@types/psl": "^1.1.3", "@types/psl": "^1.1.3",
"@types/tmp": "^0.2.6", "@types/tmp": "^0.2.6",
"@types/update-notifier": "^6.0.8", "@types/update-notifier": "^6.0.8",
"app-root-path": "^3.1.0", "app-root-path": "^3.1.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
rollup: "^4.31.0", rollup: "^4.31.0",
"rollup-plugin-typescript2": "^0.36.0", "rollup-plugin-typescript2": "^0.36.0",
tslib: "^2.8.1", tslib: "^2.8.1",
typescript: "^5.7.3" typescript: "^5.7.3"
}; };
var packageJson = { var packageJson = {
name: name, name: name,
version: version$1, version: version$1,
description: description, description: description,
engines: engines, engines: engines,
bin: bin, bin: bin,
repository: repository, repository: repository,
author: author, author: author,
keywords: keywords, keywords: keywords,
files: files, files: files,
scripts: scripts, scripts: scripts,
type: type, type: type,
exports: exports, exports: exports,
license: license, license: license,
dependencies: dependencies, dependencies: dependencies,
devDependencies: devDependencies devDependencies: devDependencies
}; };
var windows = [ var windows = [
{ {
url: "https://weread.qq.com/", url: "https://weread.qq.com/",
url_type: "web", url_type: "web",
hide_title_bar: true, hide_title_bar: true,
fullscreen: false, fullscreen: false,
width: 1200, width: 1200,
height: 780, height: 780,
resizable: true, resizable: true,
always_on_top: false, always_on_top: false,
dark_mode: false, dark_mode: false,
activation_shortcut: "", activation_shortcut: "",
disabled_web_shortcuts: false, disabled_web_shortcuts: false,
hide_on_close: true hide_on_close: true
} }
]; ];
var user_agent = { var user_agent = {
macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15", macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15",
linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
}; };
var system_tray = { var system_tray = {
macos: false, macos: false,
linux: true, linux: true,
windows: true windows: true
}; };
var system_tray_path = "icons/icon.png"; var system_tray_path = "icons/icon.png";
var inject = [ var inject = [
]; ];
var proxy_url = ""; var proxy_url = "";
var pakeConf = { var pakeConf = {
windows: windows, windows: windows,
user_agent: user_agent, user_agent: user_agent,
system_tray: system_tray, system_tray: system_tray,
system_tray_path: system_tray_path, system_tray_path: system_tray_path,
inject: inject, inject: inject,
proxy_url: proxy_url proxy_url: proxy_url
}; };
var productName$1 = "WeRead"; var productName$1 = "WeRead";
var identifier = "com.pake.weread"; var identifier = "com.pake.weread";
var version = "1.0.0"; var version = "1.0.0";
var app = { var app = {
withGlobalTauri: true, withGlobalTauri: true,
trayIcon: { trayIcon: {
iconPath: "png/weread_512.png", iconPath: "png/weread_512.png",
iconAsTemplate: false, iconAsTemplate: false,
id: "pake-tray" id: "pake-tray"
} }
}; };
var build = { var build = {
frontendDist: "../dist" frontendDist: "../dist"
}; };
var CommonConf = { var CommonConf = {
productName: productName$1, productName: productName$1,
identifier: identifier, identifier: identifier,
version: version, version: version,
app: app, app: app,
build: build build: build
}; };
var bundle$2 = { var bundle$2 = {
icon: [ icon: [
"png/weread_256.ico", "png/weread_256.ico",
"png/weread_32.ico" "png/weread_32.ico"
], ],
active: true, active: true,
resources: [ resources: [
"png/weread_32.ico" "png/weread_32.ico"
], ],
targets: [ targets: [
"msi" "msi"
], ],
windows: { windows: {
digestAlgorithm: "sha256", digestAlgorithm: "sha256",
wix: { wix: {
language: [ language: [
"en-US" "en-US"
], ],
template: "assets/main.wxs" template: "assets/main.wxs"
} }
} }
}; };
var WinConf = { var WinConf = {
bundle: bundle$2 bundle: bundle$2
}; };
var bundle$1 = { var bundle$1 = {
icon: [ icon: [
"icons/weread.icns" "icons/weread.icns"
], ],
active: true, active: true,
macOS: { macOS: {
}, },
targets: [ targets: [
"dmg" "dmg"
] ]
}; };
var MacConf = { var MacConf = {
bundle: bundle$1 bundle: bundle$1
}; };
var productName = "we-read"; var productName = "we-read";
var bundle = { var bundle = {
icon: [ icon: [
"png/weread_512.png" "png/weread_512.png"
], ],
active: true, active: true,
linux: { linux: {
deb: { deb: {
depends: [ depends: [
"curl", "curl",
"wget" "wget"
], ],
files: { files: {
"/usr/share/applications/com-pake-weread.desktop": "assets/com-pake-weread.desktop" "/usr/share/applications/com-pake-weread.desktop": "assets/com-pake-weread.desktop"
} }
} }
}, },
targets: [ targets: [
"deb", "deb",
"appimage" "appimage"
] ]
}; };
var LinuxConf = { var LinuxConf = {
productName: productName, productName: productName,
bundle: bundle bundle: bundle
}; };
const platformConfigs = { const platformConfigs = {

View File

@@ -41,6 +41,7 @@
"cli": "rollup -c rollup.config.js --watch", "cli": "rollup -c rollup.config.js --watch",
"cli:dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -w", "cli:dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -w",
"cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js", "cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js",
"format": "npx prettier --write . --ignore-unknown",
"prepublishOnly": "npm run cli:build" "prepublishOnly": "npm run cli:build"
}, },
"type": "module", "type": "module",

56
rollup.config.js vendored
View File

@@ -1,40 +1,40 @@
import path from 'path'; import path from "path";
import appRootPath from 'app-root-path'; import appRootPath from "app-root-path";
import typescript from 'rollup-plugin-typescript2'; import typescript from "rollup-plugin-typescript2";
import alias from '@rollup/plugin-alias'; import alias from "@rollup/plugin-alias";
import commonjs from '@rollup/plugin-commonjs'; import commonjs from "@rollup/plugin-commonjs";
import json from '@rollup/plugin-json'; import json from "@rollup/plugin-json";
import replace from '@rollup/plugin-replace'; import replace from "@rollup/plugin-replace";
import chalk from 'chalk'; import chalk from "chalk";
import { spawn, exec } from 'child_process'; import { spawn, exec } from "child_process";
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === "production";
const devPlugins = !isProduction ? [pakeCliDevPlugin()] : []; const devPlugins = !isProduction ? [pakeCliDevPlugin()] : [];
export default { export default {
input: isProduction ? 'bin/cli.ts' : 'bin/dev.ts', input: isProduction ? "bin/cli.ts" : "bin/dev.ts",
output: { output: {
file: isProduction ? 'dist/cli.js' : 'dist/dev.js', file: isProduction ? "dist/cli.js" : "dist/dev.js",
format: 'es', format: "es",
sourcemap: !isProduction, sourcemap: !isProduction,
}, },
watch: { watch: {
include: 'bin/**', include: "bin/**",
exclude: 'node_modules/**', exclude: "node_modules/**",
}, },
plugins: [ plugins: [
json(), json(),
typescript({ typescript({
tsconfig: 'tsconfig.json', tsconfig: "tsconfig.json",
clean: true, // Clear cache clean: true, // Clear cache
}), }),
commonjs(), commonjs(),
replace({ replace({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
preventAssignment: true, preventAssignment: true,
}), }),
alias({ alias({
entries: [{ find: '@', replacement: path.join(appRootPath.path, 'bin') }], entries: [{ find: "@", replacement: path.join(appRootPath.path, "bin") }],
}), }),
...devPlugins, ...devPlugins,
], ],
@@ -47,38 +47,38 @@ function pakeCliDevPlugin() {
let devHasStarted = false; let devHasStarted = false;
return { return {
name: 'pake-cli-dev-plugin', name: "pake-cli-dev-plugin",
buildEnd() { buildEnd() {
const command = 'node'; const command = "node";
const cliCmdArgs = ['./dist/dev.js']; const cliCmdArgs = ["./dist/dev.js"];
cliChildProcess = spawn(command, cliCmdArgs, { detached: true }); cliChildProcess = spawn(command, cliCmdArgs, { detached: true });
cliChildProcess.stdout.on('data', data => { cliChildProcess.stdout.on("data", (data) => {
console.log(chalk.green(data.toString())); console.log(chalk.green(data.toString()));
}); });
cliChildProcess.stderr.on('data', data => { cliChildProcess.stderr.on("data", (data) => {
console.error(chalk.yellow(data.toString())); console.error(chalk.yellow(data.toString()));
}); });
cliChildProcess.on('close', async code => { cliChildProcess.on("close", async (code) => {
console.log(chalk.yellow(`cli running end with code: ${code}`)); console.log(chalk.yellow(`cli running end with code: ${code}`));
if (devHasStarted) return; if (devHasStarted) return;
devHasStarted = true; devHasStarted = true;
devChildProcess = await exec( devChildProcess = await exec(
'npm run tauri dev -- --config ./src-tauri/.pake/tauri.conf.json --features cli-build', "npm run tauri dev -- --config ./src-tauri/.pake/tauri.conf.json --features cli-build",
); );
devChildProcess.stdout.on('data', data => { devChildProcess.stdout.on("data", (data) => {
console.log(chalk.green(data.toString())); console.log(chalk.green(data.toString()));
}); });
devChildProcess.stderr.on('data', data => { devChildProcess.stderr.on("data", (data) => {
console.error(chalk.yellow(data.toString())); console.error(chalk.yellow(data.toString()));
}); });
devChildProcess.on('close', code => { devChildProcess.on("close", (code) => {
console.log(chalk.yellow(`dev running end: ${code}`)); console.log(chalk.yellow(`dev running end: ${code}`));
process.exit(code); process.exit(code);
}); });

94
script/app_config.mjs vendored
View File

@@ -1,11 +1,11 @@
import pakeJson from '../src-tauri/pake.json' assert { type: 'json' }; import pakeJson from "../src-tauri/pake.json" assert { type: "json" };
import tauriJson from '../src-tauri/tauri.conf.json' assert { type: 'json' }; import tauriJson from "../src-tauri/tauri.conf.json" assert { type: "json" };
import windowsJson from '../src-tauri/tauri.windows.conf.json' assert { type: 'json' }; import windowsJson from "../src-tauri/tauri.windows.conf.json" assert { type: "json" };
import macosJson from '../src-tauri/tauri.macos.conf.json' assert { type: 'json' }; import macosJson from "../src-tauri/tauri.macos.conf.json" assert { type: "json" };
import linuxJson from '../src-tauri/tauri.linux.conf.json' assert { type: 'json' }; import linuxJson from "../src-tauri/tauri.linux.conf.json" assert { type: "json" };
import { writeFileSync, existsSync, copyFileSync } from 'fs'; import { writeFileSync, existsSync, copyFileSync } from "fs";
import os from 'os'; import os from "os";
const desktopEntry = `[Desktop Entry] const desktopEntry = `[Desktop Entry]
Encoding=UTF-8 Encoding=UTF-8
@@ -25,15 +25,15 @@ const variables = {
title: process.env.TITLE, title: process.env.TITLE,
nameZh: process.env.NAME_ZH, nameZh: process.env.NAME_ZH,
pakeConfigPath: 'src-tauri/pake.json', pakeConfigPath: "src-tauri/pake.json",
tauriConfigPath: 'src-tauri/tauri.conf.json', tauriConfigPath: "src-tauri/tauri.conf.json",
identifier: `com.pake.${process.env.NAME}`, identifier: `com.pake.${process.env.NAME}`,
linux: { linux: {
configFilePath: 'src-tauri/tauri.linux.conf.json', configFilePath: "src-tauri/tauri.linux.conf.json",
iconPath: `src-tauri/png/${process.env.NAME}_512.png`, iconPath: `src-tauri/png/${process.env.NAME}_512.png`,
productName: `com-pake-${process.env.NAME}`, productName: `com-pake-${process.env.NAME}`,
defaultIconPath: 'src-tauri/png/icon_512.png', defaultIconPath: "src-tauri/png/icon_512.png",
icon: [`png/${process.env.NAME}_512.png`], icon: [`png/${process.env.NAME}_512.png`],
desktopEntry, desktopEntry,
desktopEntryPath: `src-tauri/assets/com-pake-${process.env.NAME}.desktop`, desktopEntryPath: `src-tauri/assets/com-pake-${process.env.NAME}.desktop`,
@@ -43,17 +43,17 @@ const variables = {
}, },
}, },
macos: { macos: {
configFilePath: 'src-tauri/tauri.macos.conf.json', configFilePath: "src-tauri/tauri.macos.conf.json",
iconPath: `src-tauri/icons/${process.env.NAME}.icns`, iconPath: `src-tauri/icons/${process.env.NAME}.icns`,
defaultPath: 'src-tauri/icons/icon.icns', defaultPath: "src-tauri/icons/icon.icns",
icon: [`icons/${process.env.NAME}.icns`], icon: [`icons/${process.env.NAME}.icns`],
}, },
windows: { windows: {
configFilePath: 'src-tauri/tauri.windows.conf.json', configFilePath: "src-tauri/tauri.windows.conf.json",
iconPath: `src-tauri/png/${process.env.NAME}_32.ico`, iconPath: `src-tauri/png/${process.env.NAME}_32.ico`,
defaultPath: 'src-tauri/png/icon_32.ico', defaultPath: "src-tauri/png/icon_32.ico",
hdIconPath: `src-tauri/png/${process.env.NAME}_256.ico`, hdIconPath: `src-tauri/png/${process.env.NAME}_256.ico`,
hdDefaultPath: 'src-tauri/png/icon_256.ico', hdDefaultPath: "src-tauri/png/icon_256.ico",
icon: [`png/${process.env.NAME}_256.ico`, `png/${process.env.NAME}_32.ico`], icon: [`png/${process.env.NAME}_256.ico`, `png/${process.env.NAME}_32.ico`],
resources: [`png/${process.env.NAME}_32.ico`], resources: [`png/${process.env.NAME}_32.ico`],
}, },
@@ -69,20 +69,23 @@ let platformVariables;
let platformConfig; let platformConfig;
switch (os.platform()) { switch (os.platform()) {
case 'linux': case "linux":
platformVariables = variables.linux; platformVariables = variables.linux;
platformConfig = linuxJson; platformConfig = linuxJson;
updateDesktopEntry(); updateDesktopEntry();
break; break;
case 'darwin': case "darwin":
platformVariables = variables.macos; platformVariables = variables.macos;
platformConfig = macosJson; platformConfig = macosJson;
break; break;
case 'win32': case "win32":
platformConfig = windowsJson; platformConfig = windowsJson;
platformVariables = variables.windows; platformVariables = variables.windows;
updateResources(); updateResources();
updateIconFile(platformVariables.hdIconPath, platformVariables.hdDefaultPath); updateIconFile(
platformVariables.hdIconPath,
platformVariables.hdDefaultPath,
);
break; break;
} }
@@ -93,29 +96,29 @@ updatePlatformConfig(platformConfig, platformVariables);
save(); save();
function validate() { function validate() {
if (!('URL' in process.env)) { if (!("URL" in process.env)) {
console.log('URL is not set'); console.log("URL is not set");
process.exit(1); process.exit(1);
} }
console.log(`URL: ${process.env.URL}`); console.log(`URL: ${process.env.URL}`);
if (!('NAME' in process.env)) { if (!("NAME" in process.env)) {
console.log('NAME is not set'); console.log("NAME is not set");
process.exit(1); process.exit(1);
} }
console.log(`NAME: ${process.env.NAME}`); console.log(`NAME: ${process.env.NAME}`);
if (!('TITLE' in process.env)) { if (!("TITLE" in process.env)) {
console.log('TITLE is not set'); console.log("TITLE is not set");
process.exit(1); process.exit(1);
} }
console.log(`TITLE: ${process.env.TITLE}`); console.log(`TITLE: ${process.env.TITLE}`);
if (!('NAME_ZH' in process.env)) { if (!("NAME_ZH" in process.env)) {
console.log('NAME_ZH is not set'); console.log("NAME_ZH is not set");
process.exit(1); process.exit(1);
} }
@@ -128,18 +131,23 @@ function updatePakeJson() {
function updateTauriJson() { function updateTauriJson() {
tauriJson.productName = variables.title; tauriJson.productName = variables.title;
writeFileSync('src-tauri/tauri.conf.json', JSON.stringify(tauriJson, null, 2)); writeFileSync(
"src-tauri/tauri.conf.json",
JSON.stringify(tauriJson, null, 2),
);
} }
function updateIconFile(iconPath, defaultIconPath) { function updateIconFile(iconPath, defaultIconPath) {
if (!existsSync(iconPath)) { if (!existsSync(iconPath)) {
console.warn(`Icon for ${process.env.NAME} not found, will use default icon`); console.warn(
`Icon for ${process.env.NAME} not found, will use default icon`,
);
copyFileSync(defaultIconPath, iconPath); copyFileSync(defaultIconPath, iconPath);
} }
} }
function updatePlatformConfig(platformConfig, platformVariables) { function updatePlatformConfig(platformConfig, platformVariables) {
platformConfig.bundle['icon'] = platformVariables.icon; platformConfig.bundle["icon"] = platformVariables.icon;
platformConfig.identifier = variables.identifier; platformConfig.identifier = variables.identifier;
} }
@@ -147,17 +155,31 @@ function save() {
writeFileSync(variables.pakeConfigPath, JSON.stringify(pakeJson, null, 2)); writeFileSync(variables.pakeConfigPath, JSON.stringify(pakeJson, null, 2));
writeFileSync(variables.tauriConfigPath, JSON.stringify(tauriJson, null, 2)); writeFileSync(variables.tauriConfigPath, JSON.stringify(tauriJson, null, 2));
writeFileSync(variables.linux.configFilePath, JSON.stringify(linuxJson, null, 2)); writeFileSync(
writeFileSync(platformVariables.configFilePath, JSON.stringify(platformConfig, null, 2)); variables.linux.configFilePath,
JSON.stringify(linuxJson, null, 2),
);
writeFileSync(
platformVariables.configFilePath,
JSON.stringify(platformConfig, null, 2),
);
writeFileSync(variables.macos.configFilePath, JSON.stringify(macosJson, null, 2)); writeFileSync(
variables.macos.configFilePath,
JSON.stringify(macosJson, null, 2),
);
writeFileSync(variables.windows.configFilePath, JSON.stringify(windowsJson, null, 2)); writeFileSync(
variables.windows.configFilePath,
JSON.stringify(windowsJson, null, 2),
);
} }
function updateDesktopEntry() { function updateDesktopEntry() {
linuxJson.bundle.linux.deb.files = {}; linuxJson.bundle.linux.deb.files = {};
linuxJson.bundle.linux.deb.files[variables.linux.desktopEntryConfig.configKey] = variables.linux.desktopEntryConfig.configValue; linuxJson.bundle.linux.deb.files[
variables.linux.desktopEntryConfig.configKey
] = variables.linux.desktopEntryConfig.configValue;
writeFileSync(variables.linux.desktopEntryPath, variables.linux.desktopEntry); writeFileSync(variables.linux.desktopEntryPath, variables.linux.desktopEntry);
} }

View File

@@ -1,62 +1,73 @@
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
import axios from 'axios'; import axios from "axios";
import { execa } from 'execa'; import { execa } from "execa";
// Configuration logging // Configuration logging
const logConfiguration = () => { const logConfiguration = () => {
console.log('Welcome to use pake-cli to build app'); console.log("Welcome to use pake-cli to build app");
console.log('Node.js info in your localhost:', process.version); console.log("Node.js info in your localhost:", process.version);
console.log('\n=======================\n'); console.log("\n=======================\n");
console.log('Pake parameters:'); console.log("Pake parameters:");
console.log('url:', process.env.URL); console.log("url:", process.env.URL);
console.log('name:', process.env.NAME); console.log("name:", process.env.NAME);
console.log('icon:', process.env.ICON); console.log("icon:", process.env.ICON);
console.log('height:', process.env.HEIGHT); console.log("height:", process.env.HEIGHT);
console.log('width:', process.env.WIDTH); console.log("width:", process.env.WIDTH);
console.log('fullscreen:', process.env.FULLSCREEN); console.log("fullscreen:", process.env.FULLSCREEN);
console.log('hide-title-bar:', process.env.HIDE_TITLE_BAR); console.log("hide-title-bar:", process.env.HIDE_TITLE_BAR);
console.log('is multi arch? only for Mac:', process.env.MULTI_ARCH); console.log("is multi arch? only for Mac:", process.env.MULTI_ARCH);
console.log('targets type? only for Linux:', process.env.TARGETS); console.log("targets type? only for Linux:", process.env.TARGETS);
console.log('===========================\n'); console.log("===========================\n");
}; };
// Build parameters construction // Build parameters construction
const buildParameters = () => { const buildParameters = () => {
const params = ['cli.js', process.env.URL, '--name', process.env.NAME, '--height', process.env.HEIGHT, '--width', process.env.WIDTH]; const params = [
"cli.js",
process.env.URL,
"--name",
process.env.NAME,
"--height",
process.env.HEIGHT,
"--width",
process.env.WIDTH,
];
if (process.env.HIDE_TITLE_BAR === 'true') { if (process.env.HIDE_TITLE_BAR === "true") {
params.push('--hide-title-bar'); params.push("--hide-title-bar");
} }
if (process.env.FULLSCREEN === 'true') { if (process.env.FULLSCREEN === "true") {
params.push('--fullscreen'); params.push("--fullscreen");
} }
if (process.env.MULTI_ARCH === 'true') { if (process.env.MULTI_ARCH === "true") {
// We'll handle rustup separately since it's a different command // We'll handle rustup separately since it's a different command
params.push('--multi-arch'); params.push("--multi-arch");
} }
if (process.env.TARGETS) { if (process.env.TARGETS) {
params.push('--targets', process.env.TARGETS); params.push("--targets", process.env.TARGETS);
} }
if (process.platform === 'win32' || process.platform === 'linux') { if (process.platform === "win32" || process.platform === "linux") {
params.push('--show-system-tray'); params.push("--show-system-tray");
} }
return params; return params;
}; };
// Icon download handling // Icon download handling
const downloadIcon = async iconFile => { const downloadIcon = async (iconFile) => {
try { try {
const response = await axios.get(process.env.ICON, { responseType: 'arraybuffer' }); const response = await axios.get(process.env.ICON, {
responseType: "arraybuffer",
});
fs.writeFileSync(iconFile, response.data); fs.writeFileSync(iconFile, response.data);
return ['--icon', iconFile]; return ["--icon", iconFile];
} catch (error) { } catch (error) {
console.error('Error occurred during icon download:', error); console.error("Error occurred during icon download:", error);
throw error; throw error;
} }
}; };
@@ -64,14 +75,14 @@ const downloadIcon = async iconFile => {
// Get icon file name based on platform // Get icon file name based on platform
const getIconFileName = () => { const getIconFileName = () => {
switch (process.platform) { switch (process.platform) {
case 'linux': case "linux":
return 'icon.png'; return "icon.png";
case 'darwin': case "darwin":
return 'icon.icns'; return "icon.icns";
case 'win32': case "win32":
return 'icon.ico'; return "icon.ico";
default: default:
throw new Error('Unable to detect your OS system'); throw new Error("Unable to detect your OS system");
} }
}; };
@@ -80,47 +91,49 @@ const main = async () => {
try { try {
logConfiguration(); logConfiguration();
const cliPath = path.join(process.cwd(), 'node_modules/pake-cli'); const cliPath = path.join(process.cwd(), "node_modules/pake-cli");
process.chdir(cliPath); process.chdir(cliPath);
let params = buildParameters(); let params = buildParameters();
if (process.env.MULTI_ARCH === 'true') { if (process.env.MULTI_ARCH === "true") {
await execa('rustup', ['target', 'add', 'aarch64-apple-darwin']); await execa("rustup", ["target", "add", "aarch64-apple-darwin"]);
} }
if (process.env.ICON && process.env.ICON !== '') { if (process.env.ICON && process.env.ICON !== "") {
const iconFile = getIconFileName(); const iconFile = getIconFileName();
const iconParams = await downloadIcon(iconFile); const iconParams = await downloadIcon(iconFile);
params.push(...iconParams); params.push(...iconParams);
} else { } else {
console.log("Won't download the icon as ICON environment variable is not defined!"); console.log(
"Won't download the icon as ICON environment variable is not defined!",
);
} }
console.log('Pake parameters:', params.join(' ')); console.log("Pake parameters:", params.join(" "));
console.log('Compiling....'); console.log("Compiling....");
// Execute the CLI command // Execute the CLI command
await execa('node', params, { stdio: 'inherit' }); await execa("node", params, { stdio: "inherit" });
// Create output directory if it doesn't exist // Create output directory if it doesn't exist
if (!fs.existsSync('output')) { if (!fs.existsSync("output")) {
fs.mkdirSync('output'); fs.mkdirSync("output");
} }
// Move built files to output directory // Move built files to output directory
const files = fs.readdirSync('.'); const files = fs.readdirSync(".");
const namePattern = new RegExp(`^${process.env.NAME}\\..*$`); const namePattern = new RegExp(`^${process.env.NAME}\\..*$`);
for (const file of files) { for (const file of files) {
if (namePattern.test(file)) { if (namePattern.test(file)) {
await execa('mv', [file, path.join('output', file)]); await execa("mv", [file, path.join("output", file)]);
} }
} }
console.log('Build Success'); console.log("Build Success");
process.chdir('../..'); process.chdir("../..");
} catch (error) { } catch (error) {
console.error('Build failed:', error); console.error("Build failed:", error);
process.exit(1); process.exit(1);
} }
}; };

View File

@@ -1,15 +1,16 @@
document.addEventListener('DOMContentLoaded', () => { document.addEventListener("DOMContentLoaded", () => {
// Toast // Toast
function pakeToast(msg) { function pakeToast(msg) {
const m = document.createElement('div'); const m = document.createElement("div");
m.innerHTML = msg; m.innerHTML = msg;
m.style.cssText = m.style.cssText =
'max-width:60%;min-width: 80px;padding:0 12px;height: 32px;color: rgb(255, 255, 255);line-height: 32px;text-align: center;border-radius: 8px;position: fixed; bottom:24px;right: 28px;z-index: 999999;background: rgba(0, 0, 0,.8);font-size: 13px;'; "max-width:60%;min-width: 80px;padding:0 12px;height: 32px;color: rgb(255, 255, 255);line-height: 32px;text-align: center;border-radius: 8px;position: fixed; bottom:24px;right: 28px;z-index: 999999;background: rgba(0, 0, 0,.8);font-size: 13px;";
document.body.appendChild(m); document.body.appendChild(m);
setTimeout(function () { setTimeout(function () {
const d = 0.5; const d = 0.5;
m.style.transition = 'transform ' + d + 's ease-in, opacity ' + d + 's ease-in'; m.style.transition =
m.style.opacity = '0'; "transform " + d + "s ease-in, opacity " + d + "s ease-in";
m.style.opacity = "0";
setTimeout(function () { setTimeout(function () {
document.body.removeChild(m); document.body.removeChild(m);
}, d * 1000); }, d * 1000);

View File

@@ -1,32 +1,32 @@
const shortcuts = { const shortcuts = {
'[': () => window.history.back(), "[": () => window.history.back(),
']': () => window.history.forward(), "]": () => window.history.forward(),
'-': () => zoomOut(), "-": () => zoomOut(),
'=': () => zoomIn(), "=": () => zoomIn(),
'+': () => zoomIn(), "+": () => zoomIn(),
0: () => setZoom('100%'), 0: () => setZoom("100%"),
r: () => window.location.reload(), r: () => window.location.reload(),
ArrowUp: () => scrollTo(0, 0), ArrowUp: () => scrollTo(0, 0),
ArrowDown: () => scrollTo(0, document.body.scrollHeight), ArrowDown: () => scrollTo(0, document.body.scrollHeight),
}; };
function setZoom(zoom) { function setZoom(zoom) {
const html = document.getElementsByTagName('html')[0]; const html = document.getElementsByTagName("html")[0];
html.style.zoom = zoom; html.style.zoom = zoom;
window.localStorage.setItem('htmlZoom', zoom); window.localStorage.setItem("htmlZoom", zoom);
} }
function zoomCommon(zoomChange) { function zoomCommon(zoomChange) {
const currentZoom = window.localStorage.getItem('htmlZoom') || '100%'; const currentZoom = window.localStorage.getItem("htmlZoom") || "100%";
setZoom(zoomChange(currentZoom)); setZoom(zoomChange(currentZoom));
} }
function zoomIn() { function zoomIn() {
zoomCommon(currentZoom => `${Math.min(parseInt(currentZoom) + 10, 200)}%`); zoomCommon((currentZoom) => `${Math.min(parseInt(currentZoom) + 10, 200)}%`);
} }
function zoomOut() { function zoomOut() {
zoomCommon(currentZoom => `${Math.max(parseInt(currentZoom) - 10, 30)}%`); zoomCommon((currentZoom) => `${Math.max(parseInt(currentZoom) - 10, 30)}%`);
} }
function handleShortcut(event) { function handleShortcut(event) {
@@ -47,42 +47,45 @@ function isDownloadLink(url) {
'svg', 'swf', 'tar', 'tif', 'tiff', 'ts', 'txt', 'wav', 'webm', 'webp', 'svg', 'swf', 'tar', 'tif', 'tiff', 'ts', 'txt', 'wav', 'webm', 'webp',
'wma', 'wmv', 'xls', 'xlsx', 'xml', 'zip', 'json', 'yaml', '7zip', 'mkv', 'wma', 'wmv', 'xls', 'xlsx', 'xml', 'zip', 'json', 'yaml', '7zip', 'mkv',
]; ];
const downloadLinkPattern = new RegExp(`\\.(${fileExtensions.join('|')})$`, 'i'); const downloadLinkPattern = new RegExp(
`\\.(${fileExtensions.join("|")})$`,
"i",
);
return downloadLinkPattern.test(url); return downloadLinkPattern.test(url);
} }
document.addEventListener('DOMContentLoaded', () => { document.addEventListener("DOMContentLoaded", () => {
const tauri = window.__TAURI__; const tauri = window.__TAURI__;
const appWindow = tauri.window.getCurrentWindow(); const appWindow = tauri.window.getCurrentWindow();
const invoke = tauri.core.invoke; const invoke = tauri.core.invoke;
if (!document.getElementById('pake-top-dom')) { if (!document.getElementById("pake-top-dom")) {
const topDom = document.createElement('div'); const topDom = document.createElement("div");
topDom.id = 'pake-top-dom'; topDom.id = "pake-top-dom";
document.body.appendChild(topDom); document.body.appendChild(topDom);
} }
const domEl = document.getElementById('pake-top-dom'); const domEl = document.getElementById("pake-top-dom");
domEl.addEventListener('touchstart', () => { domEl.addEventListener("touchstart", () => {
appWindow.startDragging(); appWindow.startDragging();
}); });
domEl.addEventListener('mousedown', e => { domEl.addEventListener("mousedown", (e) => {
e.preventDefault(); e.preventDefault();
if (e.buttons === 1 && e.detail !== 2) { if (e.buttons === 1 && e.detail !== 2) {
appWindow.startDragging(); appWindow.startDragging();
} }
}); });
domEl.addEventListener('dblclick', () => { domEl.addEventListener("dblclick", () => {
appWindow.isFullscreen().then(fullscreen => { appWindow.isFullscreen().then((fullscreen) => {
appWindow.setFullscreen(!fullscreen); appWindow.setFullscreen(!fullscreen);
}); });
}); });
if (window['pakeConfig']?.disabled_web_shortcuts !== true) { if (window["pakeConfig"]?.disabled_web_shortcuts !== true) {
document.addEventListener('keyup', event => { document.addEventListener("keyup", (event) => {
if (/windows|linux/i.test(navigator.userAgent) && event.ctrlKey) { if (/windows|linux/i.test(navigator.userAgent) && event.ctrlKey) {
handleShortcut(event); handleShortcut(event);
} }
@@ -96,7 +99,7 @@ document.addEventListener('DOMContentLoaded', () => {
function collectUrlToBlobs() { function collectUrlToBlobs() {
const backupCreateObjectURL = window.URL.createObjectURL; const backupCreateObjectURL = window.URL.createObjectURL;
window.blobToUrlCaches = new Map(); window.blobToUrlCaches = new Map();
window.URL.createObjectURL = blob => { window.URL.createObjectURL = (blob) => {
const url = backupCreateObjectURL.call(window.URL, blob); const url = backupCreateObjectURL.call(window.URL, blob);
window.blobToUrlCaches.set(url, blob); window.blobToUrlCaches.set(url, blob);
return url; return url;
@@ -104,7 +107,7 @@ document.addEventListener('DOMContentLoaded', () => {
} }
function convertBlobUrlToBinary(blobUrl) { function convertBlobUrlToBinary(blobUrl) {
return new Promise(resolve => { return new Promise((resolve) => {
const blob = window.blobToUrlCaches.get(blobUrl); const blob = window.blobToUrlCaches.get(blobUrl);
const reader = new FileReader(); const reader = new FileReader();
@@ -116,7 +119,7 @@ document.addEventListener('DOMContentLoaded', () => {
} }
function downloadFromDataUri(dataURI, filename) { function downloadFromDataUri(dataURI, filename) {
const byteString = atob(dataURI.split(',')[1]); const byteString = atob(dataURI.split(",")[1]);
// write the bytes of the string to an ArrayBuffer // write the bytes of the string to an ArrayBuffer
const bufferArray = new ArrayBuffer(byteString.length); const bufferArray = new ArrayBuffer(byteString.length);
@@ -129,7 +132,7 @@ document.addEventListener('DOMContentLoaded', () => {
} }
// write the ArrayBuffer to a binary, and you're done // write the ArrayBuffer to a binary, and you're done
invoke('download_file_by_binary', { invoke("download_file_by_binary", {
params: { params: {
filename, filename,
binary: Array.from(binary), binary: Array.from(binary),
@@ -138,8 +141,8 @@ document.addEventListener('DOMContentLoaded', () => {
} }
function downloadFromBlobUrl(blobUrl, filename) { function downloadFromBlobUrl(blobUrl, filename) {
convertBlobUrlToBinary(blobUrl).then(binary => { convertBlobUrlToBinary(blobUrl).then((binary) => {
invoke('download_file_by_binary', { invoke("download_file_by_binary", {
params: { params: {
filename, filename,
binary, binary,
@@ -151,20 +154,20 @@ document.addEventListener('DOMContentLoaded', () => {
// detect blob download by createElement("a") // detect blob download by createElement("a")
function detectDownloadByCreateAnchor() { function detectDownloadByCreateAnchor() {
const createEle = document.createElement; const createEle = document.createElement;
document.createElement = el => { document.createElement = (el) => {
if (el !== 'a') return createEle.call(document, el); if (el !== "a") return createEle.call(document, el);
const anchorEle = createEle.call(document, el); const anchorEle = createEle.call(document, el);
// use addEventListener to avoid overriding the original click event. // use addEventListener to avoid overriding the original click event.
anchorEle.addEventListener( anchorEle.addEventListener(
'click', "click",
e => { (e) => {
const url = anchorEle.href; const url = anchorEle.href;
const filename = anchorEle.download || getFilenameFromUrl(url); const filename = anchorEle.download || getFilenameFromUrl(url);
if (window.blobToUrlCaches.has(url)) { if (window.blobToUrlCaches.has(url)) {
downloadFromBlobUrl(url, filename); downloadFromBlobUrl(url, filename);
// case: download from dataURL -> convert dataURL -> // case: download from dataURL -> convert dataURL ->
} else if (url.startsWith('data:')) { } else if (url.startsWith("data:")) {
downloadFromDataUri(url, filename); downloadFromDataUri(url, filename);
} }
}, },
@@ -176,12 +179,14 @@ document.addEventListener('DOMContentLoaded', () => {
} }
// process special download protocol['data:','blob:'] // process special download protocol['data:','blob:']
const isSpecialDownload = url => ['blob', 'data'].some(protocol => url.startsWith(protocol)); const isSpecialDownload = (url) =>
["blob", "data"].some((protocol) => url.startsWith(protocol));
const isDownloadRequired = (url, anchorElement, e) => anchorElement.download || e.metaKey || e.ctrlKey || isDownloadLink(url); const isDownloadRequired = (url, anchorElement, e) =>
anchorElement.download || e.metaKey || e.ctrlKey || isDownloadLink(url);
const handleExternalLink = url => { const handleExternalLink = (url) => {
invoke('plugin:shell|open', { invoke("plugin:shell|open", {
path: url, path: url,
}); });
}; };
@@ -191,23 +196,25 @@ document.addEventListener('DOMContentLoaded', () => {
try { try {
const linkUrl = new URL(url); const linkUrl = new URL(url);
const currentUrl = new URL(window.location.href); const currentUrl = new URL(window.location.href);
if (linkUrl.hostname === currentUrl.hostname) return true; if (linkUrl.hostname === currentUrl.hostname) return true;
// Extract root domain (e.g., bilibili.com from www.bilibili.com) // Extract root domain (e.g., bilibili.com from www.bilibili.com)
const getRootDomain = (hostname) => { const getRootDomain = (hostname) => {
const parts = hostname.split('.'); const parts = hostname.split(".");
return parts.length >= 2 ? parts.slice(-2).join('.') : hostname; return parts.length >= 2 ? parts.slice(-2).join(".") : hostname;
}; };
return getRootDomain(currentUrl.hostname) === getRootDomain(linkUrl.hostname); return (
getRootDomain(currentUrl.hostname) === getRootDomain(linkUrl.hostname)
);
} catch (e) { } catch (e) {
return false; return false;
} }
}; };
const detectAnchorElementClick = e => { const detectAnchorElementClick = (e) => {
const anchorElement = e.target.closest('a'); const anchorElement = e.target.closest("a");
if (anchorElement && anchorElement.href) { if (anchorElement && anchorElement.href) {
const target = anchorElement.target; const target = anchorElement.target;
@@ -216,39 +223,52 @@ document.addEventListener('DOMContentLoaded', () => {
let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl); let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl);
// Handle _blank links: same domain navigates in-app, cross-domain opens new window // Handle _blank links: same domain navigates in-app, cross-domain opens new window
if (target === '_blank') { if (target === "_blank") {
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
if (isSameDomain(absoluteUrl)) { if (isSameDomain(absoluteUrl)) {
window.location.href = absoluteUrl; window.location.href = absoluteUrl;
} else { } else {
const newWindow = originalWindowOpen.call(window, absoluteUrl, '_blank', 'width=1200,height=800,scrollbars=yes,resizable=yes'); const newWindow = originalWindowOpen.call(
window,
absoluteUrl,
"_blank",
"width=1200,height=800,scrollbars=yes,resizable=yes",
);
if (!newWindow) handleExternalLink(absoluteUrl); if (!newWindow) handleExternalLink(absoluteUrl);
} }
return; return;
} }
if (target === '_new') { if (target === "_new") {
e.preventDefault(); e.preventDefault();
handleExternalLink(absoluteUrl); handleExternalLink(absoluteUrl);
return; return;
} }
// Process download links for Rust to handle. // Process download links for Rust to handle.
if (isDownloadRequired(absoluteUrl, anchorElement, e) && !isSpecialDownload(absoluteUrl)) { if (
isDownloadRequired(absoluteUrl, anchorElement, e) &&
!isSpecialDownload(absoluteUrl)
) {
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
invoke('download_file', { params: { url: absoluteUrl, filename } }); invoke("download_file", { params: { url: absoluteUrl, filename } });
return; return;
} }
// Handle regular links: same domain allows normal navigation, cross-domain opens new window // Handle regular links: same domain allows normal navigation, cross-domain opens new window
if (!target || target === '_self') { if (!target || target === "_self") {
if (!isSameDomain(absoluteUrl)) { if (!isSameDomain(absoluteUrl)) {
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
const newWindow = originalWindowOpen.call(window, absoluteUrl, '_blank', 'width=1200,height=800,scrollbars=yes,resizable=yes'); const newWindow = originalWindowOpen.call(
window,
absoluteUrl,
"_blank",
"width=1200,height=800,scrollbars=yes,resizable=yes",
);
if (!newWindow) handleExternalLink(absoluteUrl); if (!newWindow) handleExternalLink(absoluteUrl);
} }
} }
@@ -256,7 +276,7 @@ document.addEventListener('DOMContentLoaded', () => {
}; };
// Prevent some special websites from executing in advance, before the click event is triggered. // Prevent some special websites from executing in advance, before the click event is triggered.
document.addEventListener('click', detectAnchorElementClick, true); document.addEventListener("click", detectAnchorElementClick, true);
collectUrlToBlobs(); collectUrlToBlobs();
detectDownloadByCreateAnchor(); detectDownloadByCreateAnchor();
@@ -265,20 +285,28 @@ document.addEventListener('DOMContentLoaded', () => {
const originalWindowOpen = window.open; const originalWindowOpen = window.open;
window.open = function (url, name, specs) { window.open = function (url, name, specs) {
// Apple login and google login // Apple login and google login
if (name === 'AppleAuthentication') { if (name === "AppleAuthentication") {
//do nothing //do nothing
} else if (specs && (specs.includes('height=') || specs.includes('width='))) { } else if (
specs &&
(specs.includes("height=") || specs.includes("width="))
) {
location.href = url; location.href = url;
} else { } else {
const baseUrl = window.location.origin + window.location.pathname; const baseUrl = window.location.origin + window.location.pathname;
const hrefUrl = new URL(url, baseUrl); const hrefUrl = new URL(url, baseUrl);
const absoluteUrl = hrefUrl.href; const absoluteUrl = hrefUrl.href;
// Apply same domain logic as anchor links // Apply same domain logic as anchor links
if (isSameDomain(absoluteUrl)) { if (isSameDomain(absoluteUrl)) {
// Same domain: navigate in app or open new window based on specs // Same domain: navigate in app or open new window based on specs
if (name === '_blank' || !name) { if (name === "_blank" || !name) {
return originalWindowOpen.call(window, absoluteUrl, '_blank', 'width=1200,height=800,scrollbars=yes,resizable=yes'); return originalWindowOpen.call(
window,
absoluteUrl,
"_blank",
"width=1200,height=800,scrollbars=yes,resizable=yes",
);
} else { } else {
location.href = absoluteUrl; location.href = absoluteUrl;
} }
@@ -300,27 +328,27 @@ document.addEventListener('DOMContentLoaded', () => {
// Fix Chinese input method "Enter" on Safari // Fix Chinese input method "Enter" on Safari
document.addEventListener( document.addEventListener(
'keydown', "keydown",
e => { (e) => {
if (e.keyCode === 229) e.stopPropagation(); if (e.keyCode === 229) e.stopPropagation();
}, },
true, true,
); );
}); });
document.addEventListener('DOMContentLoaded', function () { document.addEventListener("DOMContentLoaded", function () {
let permVal = 'granted'; let permVal = "granted";
window.Notification = function (title, options) { window.Notification = function (title, options) {
const { invoke } = window.__TAURI__.core; const { invoke } = window.__TAURI__.core;
const body = options?.body || ''; const body = options?.body || "";
let icon = options?.icon || ''; let icon = options?.icon || "";
// If the icon is a relative path, convert to full path using URI // If the icon is a relative path, convert to full path using URI
if (icon.startsWith('/')) { if (icon.startsWith("/")) {
icon = window.location.origin + icon; icon = window.location.origin + icon;
} }
invoke('send_notification', { invoke("send_notification", {
params: { params: {
title, title,
body, body,
@@ -329,19 +357,19 @@ document.addEventListener('DOMContentLoaded', function () {
}); });
}; };
window.Notification.requestPermission = async () => 'granted'; window.Notification.requestPermission = async () => "granted";
Object.defineProperty(window.Notification, 'permission', { Object.defineProperty(window.Notification, "permission", {
enumerable: true, enumerable: true,
get: () => permVal, get: () => permVal,
set: v => { set: (v) => {
permVal = v; permVal = v;
}, },
}); });
}); });
function setDefaultZoom() { function setDefaultZoom() {
const htmlZoom = window.localStorage.getItem('htmlZoom'); const htmlZoom = window.localStorage.getItem("htmlZoom");
if (htmlZoom) { if (htmlZoom) {
setZoom(htmlZoom); setZoom(htmlZoom);
} }
@@ -349,5 +377,5 @@ function setDefaultZoom() {
function getFilenameFromUrl(url) { function getFilenameFromUrl(url) {
const urlPath = new URL(url).pathname; const urlPath = new URL(url).pathname;
return urlPath.substring(urlPath.lastIndexOf('/') + 1); return urlPath.substring(urlPath.lastIndexOf("/") + 1);
} }

View File

@@ -1,4 +1,4 @@
window.addEventListener('DOMContentLoaded', _event => { window.addEventListener("DOMContentLoaded", (_event) => {
// Customize and transform existing functions // Customize and transform existing functions
const contentCSS = ` const contentCSS = `
#page #footer-wrapper, #page #footer-wrapper,
@@ -293,7 +293,7 @@ window.addEventListener('DOMContentLoaded', _event => {
margin-top: 15px; margin-top: 15px;
} }
`; `;
const contentStyleElement = document.createElement('style'); const contentStyleElement = document.createElement("style");
contentStyleElement.innerHTML = contentCSS; contentStyleElement.innerHTML = contentCSS;
document.head.appendChild(contentStyleElement); document.head.appendChild(contentStyleElement);
@@ -317,7 +317,7 @@ window.addEventListener('DOMContentLoaded', _event => {
} }
#root > .excalidraw-app> .excalidraw-container .App-menu.App-menu_top{ #root > .excalidraw-app> .excalidraw-container .App-menu.App-menu_top{
margin-top: 15px; margin-top: 15px;
} }
.geist-page nav.dashboard_nav__PRmJv, .geist-page nav.dashboard_nav__PRmJv,
@@ -361,7 +361,7 @@ window.addEventListener('DOMContentLoaded', _event => {
} }
body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.z-\\[21\\].flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0 > div > div > div > nav > div.flex.justify-between.h-\\[60px\\].items-center.md\\:h-header-height { body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.z-\\[21\\].flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0 > div > div > div > nav > div.flex.justify-between.h-\\[60px\\].items-center.md\\:h-header-height {
padding-top: 25px; padding-top: 25px;
} }
body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.relative.flex.h-full.max-w-full.flex-1.flex-col.overflow-hidden > main > div.composer-parent.flex.h-full.flex-col.focus-visible\\:outline-0 > div.flex-1.overflow-hidden.\\@container\\/thread > div > div.absolute.left-0.right-0 > div{ body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.relative.flex.h-full.max-w-full.flex-1.flex-col.overflow-hidden > main > div.composer-parent.flex.h-full.flex-col.focus-visible\\:outline-0 > div.flex-1.overflow-hidden.\\@container\\/thread > div > div.absolute.left-0.right-0 > div{
@@ -457,9 +457,9 @@ window.addEventListener('DOMContentLoaded', _event => {
} }
} }
`; `;
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
if (window['pakeConfig']?.hide_title_bar && isMac) { if (window["pakeConfig"]?.hide_title_bar && isMac) {
const topPaddingStyleElement = document.createElement('style'); const topPaddingStyleElement = document.createElement("style");
topPaddingStyleElement.innerHTML = topPaddingCSS; topPaddingStyleElement.innerHTML = topPaddingCSS;
document.head.appendChild(topPaddingStyleElement); document.head.appendChild(topPaddingStyleElement);
} }

View File

@@ -6,7 +6,9 @@
"linux": { "linux": {
"deb": { "deb": {
"depends": ["curl", "wget"], "depends": ["curl", "wget"],
"files": { "/usr/share/applications/com-pake-weread.desktop": "assets/com-pake-weread.desktop" } "files": {
"/usr/share/applications/com-pake-weread.desktop": "assets/com-pake-weread.desktop"
}
} }
}, },
"targets": ["deb", "appimage"] "targets": ["deb", "appimage"]

View File

@@ -2,13 +2,8 @@
"compilerOptions": { "compilerOptions": {
"module": "ESNext", "module": "ESNext",
"target": "es2020", "target": "es2020",
"types": [ "types": ["node"],
"node" "lib": ["es2020", "dom"],
],
"lib": [
"es2020",
"dom"
],
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
@@ -18,12 +13,8 @@
"outDir": "dist", "outDir": "dist",
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": [ "@/*": ["bin/*"]
"bin/*"
]
} }
}, },
"include": [ "include": ["bin/**/*"]
"bin/**/*"
]
} }