Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ec56e99
Merge branch 'release/v0.11.5'
from104 Oct 22, 2025
ad623d4
fix: upgrade @capacitor/haptics from 7.0.2 to 7.0.3
snyk-bot Dec 23, 2025
23902cb
fix: package.json to reduce vulnerabilities
snyk-bot Feb 3, 2026
dd91217
Merge pull request #97 from from104/snyk-upgrade-e819e8bc46058a490b86…
from104 Mar 6, 2026
0f20843
Merge pull request #102 from from104/snyk-fix-0cd368dd1fa237d96aa8736…
from104 Mar 6, 2026
d6a9812
fix: upgrade @capacitor/screen-orientation from 7.0.2 to 7.0.3
snyk-bot Dec 23, 2025
b16aa2a
Merge pull request #98 from from104/snyk-upgrade-b147bc03e246f0b88bac…
from104 Mar 6, 2026
2f22401
fix: upgrade @capacitor/share from 7.0.2 to 7.0.3
snyk-bot Dec 23, 2025
b41fbb4
Merge pull request #99 from from104/snyk-upgrade-b1239be743b89f1afc47…
from104 Mar 6, 2026
3c05e85
fix: upgrade @capacitor/app from 7.1.0 to 7.1.1
snyk-bot Dec 23, 2025
d5ace22
Merge pull request #100 from from104/snyk-upgrade-3fc470831d83e0299ed…
from104 Mar 6, 2026
be063b6
fix: upgrade @capacitor/status-bar from 7.0.3 to 7.0.4
snyk-bot Dec 23, 2025
edfba80
Merge pull request #101 from from104/snyk-upgrade-c8ca6c7c32e01751f08…
from104 Mar 6, 2026
56dab73
fix: package.json & yarn.lock to reduce vulnerabilities
snyk-bot Feb 10, 2026
9656900
Merge pull request #103 from from104/snyk-fix-363c949304945667e73285f…
from104 Mar 6, 2026
f1b4d13
merge: merge main into develop (Snyk dependency updates)
from104 Mar 6, 2026
c3eeb12
refactor: modernize codebase for v0.11.7
from104 Mar 7, 2026
0bbfdb2
feat: update version to 0.11.7 and stabilize Flatpak build
from104 Mar 7, 2026
c5b8d69
ci: add Electron and Flatpak build jobs to CI pipeline
from104 Mar 7, 2026
bdbed49
fix: exclude flatpak/ from Vite file watcher
from104 Mar 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: CI

on:
push:
branches: [develop, main]
pull_request:
branches: [develop, main]

jobs:
lint-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Enable Corepack
run: corepack enable

- name: Install dependencies
run: yarn install --immutable

- name: Lint
run: yarn lint

- name: Type check
run: npx vue-tsc --noEmit

- name: Test
run: yarn test

build-electron:
runs-on: ubuntu-latest
needs: lint-test

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Enable Corepack
run: corepack enable

- name: Install dependencies
run: yarn install --immutable

- name: Build Electron (linux-unpacked)
run: npx quasar build -m electron

- name: Verify build output
run: test -d dist/electron/Packaged/linux-unpacked

- name: Upload linux-unpacked artifact
uses: actions/upload-artifact@v4
with:
name: linux-unpacked
path: dist/electron/Packaged/linux-unpacked/
retention-days: 3

build-flatpak:
runs-on: ubuntu-latest
needs: build-electron
if: startsWith(github.ref, 'refs/heads/release/') || github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v4

- name: Download linux-unpacked artifact
uses: actions/download-artifact@v4
with:
name: linux-unpacked
path: flatpak/linux-unpacked/

- name: Setup Flatpak
run: |
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install -y --user flathub org.freedesktop.Platform//24.08
flatpak install -y --user flathub org.freedesktop.Sdk//24.08
flatpak install -y --user flathub org.electronjs.Electron2.BaseApp//24.08

- name: Copy icon
run: |
mkdir -p flatpak/icons
cp src-electron/icons/icon.png flatpak/icons/com.atit.qcalc.png

- name: Build Flatpak
run: |
cd flatpak
flatpak-builder --force-clean --user --disable-updates --repo=repo .flatpak-builder/build com.atit.qcalc.yml
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@ All notable changes to this project are recorded in this file.

The format is based on [Keep a Changelog] and this project follows [Semantic Versioning].

## [0.11.7] 2026-03-07

### Added

- **Vitest Test Infrastructure**: Added unit test framework with 30 tests for CalculatorMath class (`vitest.config.ts`, `src/classes/__tests__/CalculatorMath.test.ts`).
- **GitHub Actions CI/CD Pipeline**: Added automated CI workflow for linting and testing (`.github/workflows/ci.yml`).
- **Pre-commit Hooks**: Added husky + lint-staged for automated code quality checks before commits.

### Changed

- **Electron 35 → 40 Upgrade**: Upgraded Electron to version 40 with ESM compatibility fixes for the main process.
- **Vue 3.5+ useTemplateRef Migration**: Replaced legacy `ref<T | null>(null)` template ref pattern with `useTemplateRef<T>()` across 5 components (`ResultField.vue`, `SettingCard.vue`, `ToolTip.vue`, `QuasarColorPicker.vue`, `useRecordManager.ts`).
- **Any Type Removal**: Reduced `any` type usage from 16 to 1 by using Vue 3.3+ `toValue()` for `ComputedRef` unwrapping in `NarrowLayout.vue` and `WideLayout.vue`.
- **CSS v-bind → CSS Custom Properties**: Migrated Vue CSS `v-bind()` to `:style` injection with `var()` CSS custom properties in `CalcButton.vue` and `RecordCard.vue` for better performance and standards compliance.
- **CSP Security Hardening**: Split Content Security Policy configuration for development and production environments with stricter production rules.
- **Dependencies Updated**: Upgraded all dependencies to latest minor versions and applied Snyk security fixes for Capacitor packages.

### Fixed

- **Electron Main Process ESM Compatibility**: Fixed build errors caused by CJS/ESM format conflicts by using static `import fs from 'fs'` and removing top-level `await`.
- **vue-tsc Type Errors**: Fixed type checking errors in `ShowTips.vue`, `ErrorUtils.ts`, `electron-env.d.ts`, `electron-main.ts`, and `electron-preload.ts`.

## [0.11.6] 2025-12-27

### Added
Expand Down
9 changes: 7 additions & 2 deletions flatpak/com.atit.qcalc.metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@
<content_rating type="oars-1.1" />

<releases>
<release version="0.11.6" date="2026-03-01">
<release version="0.11.7" date="2026-03-07">
<description>
<p>Latest release with bug fixes and improvements.</p>
<p>Electron 40 upgrade, Vue 3.5+ modernization, Vitest test infrastructure, CI/CD pipeline, and CSP security hardening.</p>
</description>
</release>
<release version="0.11.6" date="2025-12-27">
<description>
<p>Number format per calculator feature and various bug fixes.</p>
</description>
</release>
</releases>
Expand Down
9 changes: 8 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@
name="viewport"
content="initial-scale=1, width=device-width, viewport-fit=cover<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"
/>
<% if (ctx.dev) { %>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost:* https://localhost:*; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:; connect-src 'self' https://api.freecurrencyapi.com localhost:* http://localhost:* https://localhost:* http://127.0.0.1:* https://127.0.0.1:*; font-src 'self' data:; object-src 'none'"
content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' http://localhost:* https://localhost:*; style-src 'self' 'unsafe-inline'; media-src 'self'; img-src 'self' data: content:; connect-src 'self' https://api.freecurrencyapi.com localhost:* http://localhost:* https://localhost:* http://127.0.0.1:* https://127.0.0.1:*; font-src 'self' data:; object-src 'none'"
/>
<% } else { %>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; media-src 'self'; img-src 'self' data: content:; connect-src 'self' https://api.freecurrencyapi.com; font-src 'self' data:; object-src 'none'"
/>
<% } %>
<!--
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png">
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
Expand Down
29 changes: 17 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "qcalc",
"version": "0.11.6",
"version": "0.11.7",
"description": "com.atit.qcalc",
"productName": "Q Calc",
"desktopName": "com.atit.qcalc.desktop",
Expand All @@ -18,26 +18,23 @@
"url": "https://github.com/from104/qcalc/issues"
},
"homepage": "https://github.com/from104/qcalc#readme",
"keywords": [
"calculator",
"quasar",
"vue",
"electron",
"typescript"
],
"keywords": ["calculator", "quasar", "vue", "electron", "typescript"],
"type": "module",
"scripts": {
"postinstall": "quasar prepare",
"lint": "eslint -c ./eslint.config.js \"./src*/**/*.{ts,js,cjs,mjs,vue}\"",
"format": "prettier --write \"**/*.{js,mjs,cjs,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
"test": "yarn node --experimental-vm-modules $(yarn bin jest)",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"dev": "quasar dev -m electron",
"dev:android": "quasar dev -m capacitor -T android",
"build": "quasar build -m electron",
"build:win32": "quasar build -m electron -T win32",
"build:android": "quasar build -m capacitor -T android",
"build:flatpak": "cd flatpak && bash build-flatpak.sh install",
"icons": "icongenie g -m spa,electron -i ./assets/qcalc_icon_v3.png; icongenie g -m capacitor -i ./assets/qcalc_icon_v3.png --skip-trim; rm -r src-capacitor/ios"
"icons": "icongenie g -m spa,electron -i ./assets/qcalc_icon_v3.png; icongenie g -m capacitor -i ./assets/qcalc_icon_v3.png --skip-trim; rm -r src-capacitor/ios",
"prepare": "husky"
},
"exports": {
"./src/boot/*": "./src/boot/*.ts"
Expand Down Expand Up @@ -88,17 +85,20 @@
"@types/papaparse": "^5.5.2",
"@typescript-eslint/eslint-plugin": "8.56.1",
"@typescript-eslint/parser": "8.56.1",
"@vitest/coverage-v8": "^4.0.18",
"@vue/devtools": "8.0.7",
"@vue/eslint-config-prettier": "10.2.0",
"@vue/eslint-config-typescript": "14.7.0",
"autoprefixer": "10.4.27",
"electron": "35.7.5",
"electron": "^40.8.0",
"electron-builder": "26.8.2",
"eslint": "9.39.3",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-vue": "10.8.0",
"globals": "16.5.0",
"husky": "^9.1.7",
"lint-staged": "^16.3.2",
"postcss": "8.5.8",
"prettier": "3.8.1",
"sass": "1.97.3",
Expand All @@ -107,6 +107,7 @@
"typescript": "5.9.3",
"vite": "7.3.1",
"vite-plugin-checker": "0.12.0",
"vitest": "^4.0.18",
"vue-eslint-parser": "10.4.0",
"vue-tsc": "3.2.5"
},
Expand All @@ -121,5 +122,9 @@
"ansi-regex": "5.0.1",
"strip-ansi": "6.0.1"
},
"packageManager": "yarn@4.10.3"
"packageManager": "yarn@4.10.3",
"lint-staged": {
"*.{ts,js,cjs,mjs,vue}": ["eslint -c ./eslint.config.js --fix"],
"*.{ts,js,cjs,mjs,vue,scss,html,md,json}": ["prettier --write"]
}
}
7 changes: 7 additions & 0 deletions quasar.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ export default defineConfig((/* ctx */) => {
devServer: {
open: false,
host: '0.0.0.0',
// flatpak/ 디렉토리의 대량 바이너리 파일이 inotify watcher를 소진시켜
// Electron dev 모드 실행이 차단되는 문제 방지
viteVueDevServerOptions: {
watch: {
ignored: ['**/flatpak/**'],
},
},
},

// Quasar 프레임워크 설정
Expand Down
4 changes: 4 additions & 0 deletions src-electron/electron-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// electron 패키지의 exports 필드에 types가 없어서 module: "preserve" 모드에서 타입을 찾지 못하는 문제 해결
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="../node_modules/electron/electron.d.ts" />

/**
* NodeJS 네임스페이스에 대한 타입 선언
* 이 선언은 Electron 환경에서 사용되는 프로세스 환경 변수의 타입을 정의합니다.
Expand Down
7 changes: 3 additions & 4 deletions src-electron/electron-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

// 필요한 모듈 가져오기
import { fileURLToPath } from 'url';
import fs from 'fs';
import path from 'path';
import os from 'os';
import { app, BrowserWindow, nativeTheme, ipcMain, screen } from 'electron';
Expand All @@ -32,8 +33,6 @@ const platform = process.platform || os.platform();
// Windows에서 다크 모드일 때 DevTools Extensions 제거 시도
try {
if (platform === 'win32' && nativeTheme.shouldUseDarkColors === true) {
const fs = await import('fs');
const path = await import('path');
fs.unlinkSync(path.join(app.getPath('userData'), 'DevTools Extensions'));
}
} catch (error) {
Expand Down Expand Up @@ -235,7 +234,7 @@ app
});

// 항상 위에 표시 토글 이벤트 처리
ipcMain.on('toggle-always-on-top', (_event, res) => {
ipcMain.on('toggle-always-on-top', (_event: Electron.IpcMainEvent, res: boolean) => {
mainWindow?.setAlwaysOnTop(res);
});

Expand All @@ -244,7 +243,7 @@ app
app.quit();
});
})
.catch((err) => {
.catch((err: unknown) => {
console.error('Error occurred during app preparation:', err);
});

Expand Down
9 changes: 8 additions & 1 deletion src-electron/electron-preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ contextBridge.exposeInMainWorld('electronUpdater', {
onUpdateStatus: (
callback: (status: UpdateStatusInfo['status'], info?: UpdateInfo | UpdateProgressInfo | UpdateError) => void,
) => {
ipcRenderer.on('update-status', (_event, status, info) => callback(status, info));
ipcRenderer.on(
'update-status',
(
_event: Electron.IpcRendererEvent,
status: UpdateStatusInfo['status'],
info: UpdateInfo | UpdateProgressInfo | UpdateError,
) => callback(status, info),
);
},
removeUpdateStatusListener: () => {
ipcRenderer.removeAllListeners('update-status');
Expand Down
Loading
Loading