chore: fix dependabot alerts and add dependency automation
This commit is contained in:
1 parent
c1079cee40
commit
d900d691f3
8 files changed
+692
-783
No files matched your search
@@ -0,0 +1,53 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "09:00"
|
||||
timezone: "Asia/Shanghai"
|
||||
open-pull-requests-limit: 5
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "npm"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
groups:
|
||||
production-dependencies:
|
||||
dependency-type: "production"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
development-tooling:
|
||||
dependency-type: "development"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
- dependency-name: "react"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- dependency-name: "react-dom"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- dependency-name: "vite"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "09:30"
|
||||
timezone: "Asia/Shanghai"
|
||||
open-pull-requests-limit: 3
|
||||
labels:
|
||||
- "dependencies"
|
||||
- "github-actions"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
@@ -0,0 +1,36 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
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: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Audit dependencies
|
||||
run: npm run audit
|
||||
@@ -0,0 +1,39 @@
|
||||
import js from '@eslint/js';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import tseslint from '@typescript-eslint/eslint-plugin';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import globals from 'globals';
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: ['dist/**'],
|
||||
},
|
||||
js.configs.recommended,
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'@typescript-eslint': tseslint,
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...tseslint.configs.recommended.rules,
|
||||
...reactHooks.configs.flat.recommended.rules,
|
||||
...reactRefresh.configs.vite.rules,
|
||||
},
|
||||
},
|
||||
];
|
||||
Generated
+513
-749
File diff suppressed because it is too large.
Load diff
+10
-7
@@ -5,14 +5,16 @@
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.4",
|
||||
"@types/react": "^18.2.43",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
||||
"@typescript-eslint/parser": "^8.57.1",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.26",
|
||||
"globals": "^16.5.0",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^7.2.2"
|
||||
},
|
||||
@@ -21,9 +23,10 @@
|
||||
"scripts": {
|
||||
"build": "tsc && vite build",
|
||||
"dev": "vite",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"lint": "eslint . --report-unused-disable-directives --max-warnings 0",
|
||||
"audit": "npm audit --audit-level=moderate",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"type": "module",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { renderQRToCanvas } from '../lib/qrGenerator';
|
||||
import { QRCodeInstance, QRConfig, QRInfo } from '../types/qr';
|
||||
import './PreviewPanel.css';
|
||||
@@ -14,14 +14,23 @@ interface PreviewPanelProps {
|
||||
|
||||
export function PreviewPanel({ qr, config, info, onExportPNG, onExportSVG, onExportConfig }: PreviewPanelProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
const previewKey = useMemo(
|
||||
() => JSON.stringify({
|
||||
content: config.content,
|
||||
version: info?.version ?? config.version,
|
||||
errorCorrectionLevel: config.errorCorrectionLevel,
|
||||
maskPattern: config.maskPattern,
|
||||
quietZone: config.quietZone,
|
||||
moduleStyle: config.moduleStyle,
|
||||
foregroundColor: config.foregroundColor,
|
||||
backgroundColor: config.backgroundColor,
|
||||
}),
|
||||
[config, info?.version],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!qr || !canvasRef.current) return;
|
||||
|
||||
setIsAnimating(true);
|
||||
const timer = setTimeout(() => setIsAnimating(false), 500);
|
||||
|
||||
try {
|
||||
const canvas = renderQRToCanvas(qr, config, 512);
|
||||
const ctx = canvasRef.current.getContext('2d');
|
||||
@@ -33,8 +42,6 @@ export function PreviewPanel({ qr, config, info, onExportPNG, onExportSVG, onExp
|
||||
} catch (error) {
|
||||
console.error('Error rendering QR code:', error);
|
||||
}
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [qr, config]);
|
||||
|
||||
if (!qr || !info) {
|
||||
@@ -53,7 +60,7 @@ export function PreviewPanel({ qr, config, info, onExportPNG, onExportSVG, onExp
|
||||
<div className="preview-panel glass-card fade-in">
|
||||
<h2 className="panel-title">Preview</h2>
|
||||
|
||||
<div className={`preview-container ${isAnimating ? 'animating' : ''}`}>
|
||||
<div key={previewKey} className="preview-container animating">
|
||||
<canvas ref={canvasRef} className="preview-canvas" />
|
||||
</div>
|
||||
|
||||
|
||||
+21
-17
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { generateQRCode } from "../lib/qrGenerator";
|
||||
import { QRCodeInstance, QRConfig, QRInfo } from "../types/qr";
|
||||
|
||||
@@ -16,9 +16,6 @@ const DEFAULT_CONFIG: QRConfig = {
|
||||
|
||||
export function useQRCode() {
|
||||
const [config, setConfig] = useState<QRConfig>(DEFAULT_CONFIG);
|
||||
const [qr, setQr] = useState<QRCodeInstance | null>(null);
|
||||
const [info, setInfo] = useState<QRInfo | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const updateConfig = useCallback((updates: Partial<QRConfig>) => {
|
||||
setConfig((prev) => ({ ...prev, ...updates }));
|
||||
@@ -28,25 +25,32 @@ export function useQRCode() {
|
||||
setConfig(DEFAULT_CONFIG);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const { qr, info, error } = useMemo<{
|
||||
qr: QRCodeInstance | null;
|
||||
info: QRInfo | null;
|
||||
error: string | null;
|
||||
}>(() => {
|
||||
if (!config.content) {
|
||||
setQr(null);
|
||||
setInfo(null);
|
||||
setError(null);
|
||||
return;
|
||||
return {
|
||||
qr: null,
|
||||
info: null,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const result = generateQRCode(config);
|
||||
setQr(result.qr);
|
||||
setInfo(result.info);
|
||||
setError(null);
|
||||
return {
|
||||
qr: result.qr,
|
||||
info: result.info,
|
||||
error: null,
|
||||
};
|
||||
} catch (err) {
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Failed to generate QR code"
|
||||
);
|
||||
setQr(null);
|
||||
setInfo(null);
|
||||
return {
|
||||
qr: null,
|
||||
info: null,
|
||||
error: err instanceof Error ? err.message : "Failed to generate QR code",
|
||||
};
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
QRInfo,
|
||||
} from "../types/qr";
|
||||
|
||||
type QRCodeVersion = Parameters<typeof qrcode>[0];
|
||||
|
||||
// Map error correction levels to library constants
|
||||
const EC_LEVEL_MAP: Record<ErrorCorrectionLevel, ErrorCorrectionLevel> = {
|
||||
L: "L",
|
||||
@@ -79,7 +81,7 @@ export function generateQRCode(config: QRConfig): {
|
||||
}
|
||||
|
||||
// Create QR code
|
||||
const qr = qrcode(version as any, ecLevel);
|
||||
const qr = qrcode(version as QRCodeVersion, ecLevel);
|
||||
qr.addData(config.content);
|
||||
qr.make();
|
||||
|
||||
@@ -185,7 +187,7 @@ export function renderQRToCanvas(
|
||||
case "square":
|
||||
ctx.fillRect(x, y, moduleSize, moduleSize);
|
||||
break;
|
||||
case "rounded":
|
||||
case "rounded": {
|
||||
ctx.beginPath();
|
||||
const radius = moduleSize * 0.3;
|
||||
ctx.moveTo(x + radius, y);
|
||||
@@ -205,6 +207,7 @@ export function renderQRToCanvas(
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
break;
|
||||
}
|
||||
case "dots":
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
|
||||
Reference in new issue
Block a user