├── public ├── CNAME └── favicon.ico ├── .npmrc ├── postcss.config.js ├── pages ├── _app.js ├── layout.js └── index.js ├── components ├── picker.module.css ├── color.js ├── picker.js ├── saver.js ├── control.js └── canvas.js ├── tailwind.config.js ├── assets ├── left.svg ├── right.svg ├── load.svg ├── save.svg ├── image.svg └── github.svg ├── next.config.js ├── README.md ├── package.json ├── .gitignore ├── styles └── globals.css ├── .github └── workflows │ └── gh-pages.yml ├── LICENSE └── pnpm-lock.yaml /public/CNAME: -------------------------------------------------------------------------------- 1 | px.fzf404.art -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | 3 | registry=https://registry.npmmirror.com -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fzf404/Pixxel/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return 5 | } 6 | 7 | export default MyApp 8 | -------------------------------------------------------------------------------- /components/picker.module.css: -------------------------------------------------------------------------------- 1 | .popover { 2 | margin-left: 78px; 3 | position: absolute; 4 | z-index: 10; 5 | } 6 | 7 | .cover { 8 | position: fixed; 9 | top: 0px; 10 | right: 0px; 11 | bottom: 0px; 12 | left: 0px; 13 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | darkMode: 'class', 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx}', 5 | './components/**/*.{js,ts,jsx,tsx}', 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } 12 | -------------------------------------------------------------------------------- /assets/left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | module.exports = { 3 | // 严格模式 4 | reactStrictMode: true, 5 | // 相对路径部署 6 | assetPrefix: '.', 7 | // webpack 配置 8 | webpack(config) { 9 | // svg loader 10 | config.module.rules.push({ 11 | test: /\.svg$/, 12 | use: ['@svgr/webpack'], 13 | }) 14 | return config 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixxel 2 | 3 | > 优雅的像素画工具 4 | > 5 | > 使用 React、Next.js、Tailwindcss 开发 6 | > 7 | > [px.fzf404.art](https://px.fzf404.art/) 8 | 9 | ![Pixxel](https://img.fzf404.art/pixxel/show.webp) 10 | 11 | ## 更新记录 12 | 13 | > 更多功能欢迎来提 issue 14 | 15 | - [x] 基本绘制 (鼠标左键) / 擦除 (鼠标右键) 16 | - [x] 颜色选择 17 | - [x] 动态调整画布尺寸 18 | - [x] 移动端适配 19 | - [x] 保存/加载 20 | - [ ] 撤销操作 21 | - [ ] 发布 NPM 包 22 | - [ ] ... 23 | - [ ] 教程 24 | - [ ] 社区 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pixxel", 3 | "version": "0.1.2", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build && next export" 8 | }, 9 | "dependencies": { 10 | "file-saver": "^2.0.5", 11 | "next": "^13.1.1", 12 | "react": "^18.2.0", 13 | "react-color": "^2.19.3", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@svgr/webpack": "^6.5.1", 18 | "autoprefixer": "^10.4.13", 19 | "postcss": "^8.4.20", 20 | "tailwindcss": "^3.2.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /assets/load.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | -------------------------------------------------------------------------------- /assets/save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /assets/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | height: 100%; 5 | overflow: hidden; 6 | user-select: none; 7 | } 8 | 9 | @tailwind base; 10 | @tailwind components; 11 | @tailwind utilities; 12 | 13 | 14 | .color-circle { 15 | @apply relative inline-flex items-center justify-center mx-2 w-10 h-10 rounded-full shadow-md shadow-gray-400 ring-offset-4; 16 | } 17 | 18 | .btn { 19 | @apply relative inline-flex items-center px-4 py-2 border text-sm font-medium; 20 | } 21 | 22 | .btn-sm { 23 | @apply relative inline-flex items-center p-2 border text-sm font-medium; 24 | } 25 | 26 | .btn-round { 27 | @apply btn rounded-lg shadow-lg ; 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: gh-pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | 15 | - name: Pnpm 16 | uses: pnpm/action-setup@v2 17 | with: 18 | version: 7 19 | 20 | - name: Node 21 | uses: actions/setup-node@v3 22 | with: 23 | cache: pnpm 24 | node-version: 16 25 | 26 | - name: Setup 27 | run: | 28 | pnpm install 29 | 30 | - name: Build 31 | run: | 32 | pnpm build 33 | 34 | - name: Deploy 35 | uses: peaceiris/actions-gh-pages@v3 36 | with: 37 | github_token: ${{ secrets.GITHUB_TOKEN }} 38 | publish_dir: out 39 | -------------------------------------------------------------------------------- /pages/layout.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: fzf404 3 | * @Date: 2022-01-06 14:19:45 4 | * @LastEditTime: 2022-12-28 01:33:36 5 | * @Description: 基础框架 6 | */ 7 | 8 | import Head from 'next/head' 9 | 10 | const baiduAnalytics = () => { 11 | return { 12 | __html: ` 13 | var _hmt = _hmt || []; 14 | (function() { 15 | var hm = document.createElement("script"); 16 | hm.src = "https://hm.baidu.com/hm.js?a25d3a09abf9ccb1a8385018d43843b2"; 17 | var s = document.getElementsByTagName("script")[0]; 18 | s.parentNode.insertBefore(hm, s); 19 | })(); 20 | `, 21 | } 22 | } 23 | 24 | const Layout = ({ children }) => { 25 | return ( 26 |
27 | 28 | Pixxel 29 | 30 |