init
This commit is contained in:
2025-07-28 22:43:00 +08:00
parent b12e790507
commit c678630298
5 changed files with 342 additions and 0 deletions

46
CHANGELOG.md Normal file
View File

@@ -0,0 +1,46 @@
# 更新日誌
本專案的所有重要變更都會記錄在此檔案中。
格式基於 [Keep a Changelog](https://keepachangelog.com/zh-TW/1.0.0/)
且本專案遵循 [Semantic Versioning](https://semver.org/lang/zh-TW/)。
## [未發布]
### 新增
- 新功能 A
- 新功能 B
### 變更
- 變更功能 A
- 變更功能 B
### 修復
- 修復 Bug A
- 修復 Bug B
## [1.0.0] - 2024-01-01
### 新增
- 初始版本發布
- 基本圖片上傳功能
- React 前端介面
- Flask 後端 API
- 圖片預覽功能
- 響應式設計
- Tailwind CSS 樣式
### 技術特色
- Flask 3.0.0 後端框架
- React 19 前端框架
- Flask-CORS 跨域支援
- 現代化 UI/UX 設計
- 支援多種圖片格式
---
## 版本說明
- **主要版本**:不相容的 API 變更
- **次要版本**:向後相容的新功能
- **修補版本**:向後相容的 Bug 修復

168
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,168 @@
# 貢獻指南
感謝您對 ImageZoom 專案的關注!我們歡迎所有形式的貢獻。
## 如何貢獻
### 報告 Bug
如果您發現了 Bug
1. 檢查 [Issues](https://github.com/your-username/imagezoom/issues) 是否已經有人報告過
2. 如果沒有,請建立新的 Issue並包含
- 詳細的 Bug 描述
- 重現步驟
- 預期行為和實際行為
- 作業系統和瀏覽器版本
- 錯誤訊息或截圖
### 功能請求
如果您有新的功能想法:
1. 檢查現有的 Issues 和 Pull Requests
2. 建立新的 Issue描述
- 功能需求
- 使用場景
- 預期效果
### 程式碼貢獻
#### 開發環境設定
1. **Fork 專案**
```bash
git clone https://github.com/your-username/imagezoom.git
cd imagezoom
```
2. **建立虛擬環境**
```bash
python -m venv venv
source venv/bin/activate # Linux/Mac
# 或
venv\Scripts\activate # Windows
```
3. **安裝依賴**
```bash
pip install -r requirements.txt
cd frontend && npm install
```
#### 開發流程
1. **建立功能分支**
```bash
git checkout -b feature/your-feature-name
```
2. **開發功能**
- 遵循現有的程式碼風格
- 撰寫測試(如果適用)
- 確保所有測試通過
3. **提交變更**
```bash
git add .
git commit -m "feat: 新增功能描述"
```
4. **推送到分支**
```bash
git push origin feature/your-feature-name
```
5. **建立 Pull Request**
- 前往 GitHub 建立 Pull Request
- 填寫 PR 模板
- 等待審查
#### 提交訊息規範
我們使用 [Conventional Commits](https://www.conventionalcommits.org/) 規範:
- `feat:` 新功能
- `fix:` Bug 修復
- `docs:` 文件更新
- `style:` 程式碼格式調整
- `refactor:` 重構
- `test:` 測試相關
- `chore:` 建置工具或輔助工具的變動
範例:
```
feat: 新增圖片縮放功能
fix: 修復上傳檔案大小限制問題
docs: 更新 API 文件
```
#### 程式碼風格
**Python (後端)**
- 遵循 PEP 8 規範
- 使用 4 個空格縮排
- 行長度限制在 79 字元內
- 使用有意義的變數和函數名稱
**JavaScript (前端)**
- 使用 ESLint 和 Prettier
- 遵循 React 最佳實踐
- 使用有意義的組件和函數名稱
#### 測試
**後端測試**
```bash
# 執行測試
python -m pytest
# 執行測試並顯示覆蓋率
python -m pytest --cov=app
```
**前端測試**
```bash
cd frontend
npm test
```
## Pull Request 審查流程
1. **自動檢查**
- CI/CD 流程會自動執行測試
- 程式碼風格檢查
- 安全性掃描
2. **人工審查**
- 至少需要一位維護者審查
- 可能需要修改或改進
3. **合併**
- 審查通過後會合併到主分支
- 會自動部署到測試環境
## 行為準則
我們致力於建立一個友善和包容的社群環境:
- 尊重所有貢獻者
- 使用友善和建設性的語言
- 接受建設性的批評
- 專注於問題本身,而非個人
## 聯絡方式
如果您有任何問題或建議:
- 建立 [Issue](https://github.com/your-username/imagezoom/issues)
- 發送 Email 至 [your-email@example.com]
- 加入我們的 [Discord 社群](https://discord.gg/your-server)
## 致謝
感謝所有為這個專案做出貢獻的開發者!
---
**注意:** 請確保您同意本專案的 [LICENSE](LICENSE) 條款。

63
accessible-emoji.js Normal file
View File

@@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _emojiRegex = _interopRequireDefault(require("emoji-regex"));
var _jsxAstUtils = require("jsx-ast-utils");
var _safeRegexTest = _interopRequireDefault(require("safe-regex-test"));
var _schemas = require("../util/schemas");
var _getElementType = _interopRequireDefault(require("../util/getElementType"));
var _isHiddenFromScreenReader = _interopRequireDefault(require("../util/isHiddenFromScreenReader"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
/**
* @fileoverview Enforce emojis are wrapped in <span> and provide screen reader access.
* @author Ethan Cohen
*/
// ----------------------------------------------------------------------------
// Rule Definition
// ----------------------------------------------------------------------------
var errorMessage = 'Emojis should be wrapped in <span>, have role="img", and have an accessible description with aria-label or aria-labelledby.';
var schema = (0, _schemas.generateObjSchema)();
var _default = exports["default"] = {
meta: {
docs: {
description: 'Enforce emojis are wrapped in `<span>` and provide screen reader access.',
url: 'https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/accessible-emoji.md'
},
deprecated: true,
schema: [schema]
},
create: function create(context) {
var elementType = (0, _getElementType["default"])(context);
var testEmoji = (0, _safeRegexTest["default"])((0, _emojiRegex["default"])());
return {
JSXOpeningElement: function JSXOpeningElement(node) {
var literalChildValue = node.parent.children.find(function (child) {
return child.type === 'Literal' || child.type === 'JSXText';
});
if (literalChildValue && testEmoji(literalChildValue.value)) {
var elementIsHidden = (0, _isHiddenFromScreenReader["default"])(elementType(node), node.attributes);
if (elementIsHidden) {
return; // emoji is decorative
}
var rolePropValue = (0, _jsxAstUtils.getLiteralPropValue)((0, _jsxAstUtils.getProp)(node.attributes, 'role'));
var ariaLabelProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-label');
var arialLabelledByProp = (0, _jsxAstUtils.getProp)(node.attributes, 'aria-labelledby');
var hasLabel = ariaLabelProp !== undefined || arialLabelledByProp !== undefined;
var isSpan = elementType(node) === 'span';
if (hasLabel === false || rolePropValue !== 'img' || isSpan === false) {
context.report({
node,
message: errorMessage
});
}
}
}
};
}
};
module.exports = exports.default;

36
app.py Normal file
View File

@@ -0,0 +1,36 @@
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import os
app = Flask(__name__)
CORS(app)
UPLOAD_FOLDER = 'uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
if file:
filename = file.filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return jsonify({'success': True, 'filename': filename})
@app.route('/images', methods=['GET'])
def get_images():
images = os.listdir(app.config['UPLOAD_FOLDER'])
return jsonify(images)
@app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
if __name__ == '__main__':
app.run(debug=True)

29
docker-compose.yml Normal file
View File

@@ -0,0 +1,29 @@
version: '3.8'
services:
imagezoom:
build: .
ports:
- "5000:5000"
volumes:
- ./uploads:/app/uploads
- ./templates:/app/templates
environment:
- FLASK_ENV=development
- FLASK_DEBUG=1
restart: unless-stopped
# 可選:如果需要資料庫
# db:
# image: postgres:15
# environment:
# POSTGRES_DB: imagezoom
# POSTGRES_USER: postgres
# POSTGRES_PASSWORD: password
# volumes:
# - postgres_data:/var/lib/postgresql/data
# ports:
# - "5432:5432"
# volumes:
# postgres_data: