mirror of
				https://github.com/lutinglt/gitea-github-theme.git
				synced 2025-10-27 22:40:30 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			v1.24.0.25
			...
			77fe50a4cc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 77fe50a4cc | ||
|   | 0f9ee02a7d | ||
|   | 55ac3af9b7 | 
| @@ -11,8 +11,6 @@ indent_style = space | |||||||
| end_of_line = lf | end_of_line = lf | ||||||
| insert_final_newline = true | insert_final_newline = true | ||||||
| trim_trailing_whitespace = true | trim_trailing_whitespace = true | ||||||
|  |  | ||||||
| [*.{css,scss,ts}] |  | ||||||
| max_line_length = 120 | max_line_length = 120 | ||||||
|  |  | ||||||
| # documentation, utils | # documentation, utils | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/release-template.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/release-template.md
									
									
									
									
										vendored
									
									
								
							| @@ -4,4 +4,4 @@ | |||||||
|  |  | ||||||
| ## 🎈 Perf | ## 🎈 Perf | ||||||
|  |  | ||||||
| ## 🐞 Fix | ## 🐞 Fix | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,7 +17,7 @@ jobs: | |||||||
|       - name: Create release |       - name: Create release | ||||||
|         run: | |         run: | | ||||||
|           export TZ=Asia/Shanghai |           export TZ=Asia/Shanghai | ||||||
|           TAG="v$(./build.ts).$(date +%y%m%d%H%M)" |           TAG="v$(deno run -q version).$(date +%y%m%d%H%M)" | ||||||
|           gh release create "$TAG" dist/* --notes-file .github/release.md --draft -t $TAG |           gh release create "$TAG" dist/* --notes-file .github/release.md --draft -t $TAG | ||||||
|         env: |         env: | ||||||
|           GH_TOKEN: ${{ github.token }} |           GH_TOKEN: ${{ github.token }} | ||||||
|   | |||||||
| @@ -1,5 +0,0 @@ | |||||||
| dist/ |  | ||||||
| node_modules/ |  | ||||||
| package-lock.json |  | ||||||
| deno.json |  | ||||||
| deno.lock |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| { |  | ||||||
|   "printWidth": 120, |  | ||||||
|   "tabWidth": 2, |  | ||||||
|   "useTabs": false, |  | ||||||
|   "semi": true, |  | ||||||
|   "singleQuote": false, |  | ||||||
|   "quoteProps": "as-needed", |  | ||||||
|   "jsxSingleQuote": false, |  | ||||||
|   "trailingComma": "none", |  | ||||||
|   "bracketSpacing": true, |  | ||||||
|   "bracketSameLine": true, |  | ||||||
|   "arrowParens": "avoid", |  | ||||||
|   "proseWrap": "always", |  | ||||||
|   "htmlWhitespaceSensitivity": "css", |  | ||||||
|   "endOfLine": "lf" |  | ||||||
| } |  | ||||||
| @@ -4,4 +4,4 @@ | |||||||
| | styles/components | 具体页面的元素单独风格       | | | styles/components | 具体页面的元素单独风格       | | ||||||
| | styles/public     | 适用大部分页面的元素默认风格 | | | styles/public     | 适用大部分页面的元素默认风格 | | ||||||
| | themes            | 颜色主题                     | | | themes            | 颜色主题                     | | ||||||
| | themes/\<theme>   | 具体颜色主题自己的颜色或风格 | | | themes/\<theme>   | 具体颜色主题自己的颜色或风格 | | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| # gitea-github-theme | # gitea-github-theme | ||||||
|  |  | ||||||
| 尽量保持与 GitHub Dark 相同样式的 Gitea 主题 | 尽量保持与 GitHub 相同样式的 Gitea 主题 | ||||||
|  |  | ||||||
| ### 主题说明 | ### 主题说明 | ||||||
|  |  | ||||||
| @@ -42,30 +42,6 @@ THEMES = gitea-dark, github | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## 构建 |  | ||||||
|  |  | ||||||
| ### 克隆仓库 |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| git clone https://github.com/lutinglt/gitea-github-theme.git |  | ||||||
| cd gitea-github-theme |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### 使用 deno (推荐) |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| deno run build |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### 使用 nodejs & npm |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| npm install |  | ||||||
| npm run build |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| 查看用于 Gitea 的主题文件: `dist/theme-github.css` |  | ||||||
|  |  | ||||||
| ## 贡献 | ## 贡献 | ||||||
|  |  | ||||||
| 欢迎提交 Issue 或 Pull Request | 欢迎提交 Issue 或 Pull Request | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								build.js
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								build.js
									
									
									
									
									
								
							| @@ -1,34 +0,0 @@ | |||||||
| import * as process from "node:process"; |  | ||||||
| import * as fs from "node:fs"; |  | ||||||
| import * as sass from "sass"; |  | ||||||
| import * as yaml from "js-yaml"; |  | ||||||
|  |  | ||||||
| async function compile(inputFile) { |  | ||||||
|   return (await sass.compileAsync(inputFile, { sourceMap: false, style: "compressed" })).css; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function generateTheme(themePath) { |  | ||||||
|   try { |  | ||||||
|     const fileContent = fs.readFileSync(themePath); |  | ||||||
|     const data = yaml.load(fileContent); |  | ||||||
|     console.log(data.gitea.version); |  | ||||||
|  |  | ||||||
|     fs.mkdirSync("dist", { recursive: true }); |  | ||||||
|     const styles = await compile("src/styles/styles.scss"); |  | ||||||
|     for (const theme of data.gitea.themes) { |  | ||||||
|       const inputFile = `src/themes/${theme}.scss`; |  | ||||||
|       const outputFile = `dist/theme-github-${theme}.css`; |  | ||||||
|       const result = await compile(inputFile); |  | ||||||
|       fs.writeFileSync(outputFile, `${styles}${result}`); |  | ||||||
|     } |  | ||||||
|   } catch (error) { |  | ||||||
|     let e = error; |  | ||||||
|     if (error instanceof Error) { |  | ||||||
|       e = error.message; |  | ||||||
|     } |  | ||||||
|     console.error("Build failed:", e); |  | ||||||
|     process.exit(1); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| generateTheme("theme.yml"); |  | ||||||
							
								
								
									
										43
									
								
								build.ts
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								build.ts
									
									
									
									
									
								
							| @@ -1,43 +0,0 @@ | |||||||
| #!/usr/bin/env -S deno run -A --allow-scripts -q |  | ||||||
|  |  | ||||||
| import * as sass from "npm:sass"; |  | ||||||
| import * as yaml from "npm:js-yaml"; |  | ||||||
|  |  | ||||||
| interface Gitea { |  | ||||||
|   version: string; |  | ||||||
|   themes: [string]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| interface ThemeInfo { |  | ||||||
|   gitea: Gitea; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function compile(inputFile: string) { |  | ||||||
|   return (await sass.compileAsync(inputFile, { sourceMap: false, style: "compressed" })).css; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function generateTheme(themePath: string) { |  | ||||||
|   try { |  | ||||||
|     const fileContent = await Deno.readTextFile(themePath); |  | ||||||
|     const data: ThemeInfo = yaml.load(fileContent); |  | ||||||
|     console.log(data.gitea.version); |  | ||||||
|  |  | ||||||
|     await Deno.mkdir("dist", { recursive: true }); |  | ||||||
|     const styles = await compile("src/styles/styles.scss"); |  | ||||||
|     for (const theme of data.gitea.themes) { |  | ||||||
|       const inputFile = `src/themes/${theme}.scss`; |  | ||||||
|       const outputFile = `dist/theme-github-${theme}.css`; |  | ||||||
|       const result = await compile(inputFile); |  | ||||||
|       await Deno.writeTextFile(outputFile, `${styles}${result}`); |  | ||||||
|     } |  | ||||||
|   } catch (error) { |  | ||||||
|     let e = error; |  | ||||||
|     if (error instanceof Error) { |  | ||||||
|       e = error.message; |  | ||||||
|     } |  | ||||||
|     console.error("Build failed:", e); |  | ||||||
|     Deno.exit(1); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| generateTheme("theme.yml"); |  | ||||||
							
								
								
									
										11
									
								
								deno.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								deno.json
									
									
									
									
									
								
							| @@ -1,11 +0,0 @@ | |||||||
| { |  | ||||||
|   "nodeModulesDir": "auto", |  | ||||||
|   "fmt": { |  | ||||||
|     "options": { |  | ||||||
|       "lineWidth": 120 |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   "tasks": { |  | ||||||
|     "build": "deno -A --allow-scripts build.ts" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										170
									
								
								deno.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										170
									
								
								deno.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,170 +0,0 @@ | |||||||
| { |  | ||||||
|   "version": "4", |  | ||||||
|   "specifiers": { |  | ||||||
|     "npm:@types/node@*": "22.5.4", |  | ||||||
|     "npm:js-yaml@*": "4.1.0", |  | ||||||
|     "npm:js-yaml@^4.1.0": "4.1.0", |  | ||||||
|     "npm:sass@*": "1.84.0", |  | ||||||
|     "npm:sass@1.84.0": "1.84.0", |  | ||||||
|     "npm:sass@^1.83.0": "1.84.0" |  | ||||||
|   }, |  | ||||||
|   "npm": { |  | ||||||
|     "@parcel/watcher-android-arm64@2.5.1": { |  | ||||||
|       "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-darwin-arm64@2.5.1": { |  | ||||||
|       "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-darwin-x64@2.5.1": { |  | ||||||
|       "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-freebsd-x64@2.5.1": { |  | ||||||
|       "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-linux-arm-glibc@2.5.1": { |  | ||||||
|       "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-linux-arm-musl@2.5.1": { |  | ||||||
|       "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-linux-arm64-glibc@2.5.1": { |  | ||||||
|       "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-linux-arm64-musl@2.5.1": { |  | ||||||
|       "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-linux-x64-glibc@2.5.1": { |  | ||||||
|       "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-linux-x64-musl@2.5.1": { |  | ||||||
|       "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-win32-arm64@2.5.1": { |  | ||||||
|       "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-win32-ia32@2.5.1": { |  | ||||||
|       "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher-win32-x64@2.5.1": { |  | ||||||
|       "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==" |  | ||||||
|     }, |  | ||||||
|     "@parcel/watcher@2.5.1": { |  | ||||||
|       "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "@parcel/watcher-android-arm64", |  | ||||||
|         "@parcel/watcher-darwin-arm64", |  | ||||||
|         "@parcel/watcher-darwin-x64", |  | ||||||
|         "@parcel/watcher-freebsd-x64", |  | ||||||
|         "@parcel/watcher-linux-arm-glibc", |  | ||||||
|         "@parcel/watcher-linux-arm-musl", |  | ||||||
|         "@parcel/watcher-linux-arm64-glibc", |  | ||||||
|         "@parcel/watcher-linux-arm64-musl", |  | ||||||
|         "@parcel/watcher-linux-x64-glibc", |  | ||||||
|         "@parcel/watcher-linux-x64-musl", |  | ||||||
|         "@parcel/watcher-win32-arm64", |  | ||||||
|         "@parcel/watcher-win32-ia32", |  | ||||||
|         "@parcel/watcher-win32-x64", |  | ||||||
|         "detect-libc", |  | ||||||
|         "is-glob", |  | ||||||
|         "micromatch", |  | ||||||
|         "node-addon-api" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "@types/node@22.5.4": { |  | ||||||
|       "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "undici-types" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "argparse@2.0.1": { |  | ||||||
|       "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" |  | ||||||
|     }, |  | ||||||
|     "braces@3.0.3": { |  | ||||||
|       "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "fill-range" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "chokidar@4.0.3": { |  | ||||||
|       "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "readdirp" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "detect-libc@1.0.3": { |  | ||||||
|       "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==" |  | ||||||
|     }, |  | ||||||
|     "fill-range@7.1.1": { |  | ||||||
|       "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "to-regex-range" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "immutable@5.0.3": { |  | ||||||
|       "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==" |  | ||||||
|     }, |  | ||||||
|     "is-extglob@2.1.1": { |  | ||||||
|       "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" |  | ||||||
|     }, |  | ||||||
|     "is-glob@4.0.3": { |  | ||||||
|       "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "is-extglob" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "is-number@7.0.0": { |  | ||||||
|       "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" |  | ||||||
|     }, |  | ||||||
|     "js-yaml@4.1.0": { |  | ||||||
|       "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "argparse" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "micromatch@4.0.8": { |  | ||||||
|       "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "braces", |  | ||||||
|         "picomatch" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "node-addon-api@7.1.1": { |  | ||||||
|       "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==" |  | ||||||
|     }, |  | ||||||
|     "picomatch@2.3.1": { |  | ||||||
|       "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" |  | ||||||
|     }, |  | ||||||
|     "readdirp@4.1.1": { |  | ||||||
|       "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==" |  | ||||||
|     }, |  | ||||||
|     "sass@1.84.0": { |  | ||||||
|       "integrity": "sha512-XDAbhEPJRxi7H0SxrnOpiXFQoUJHwkR2u3Zc4el+fK/Tt5Hpzw5kkQ59qVDfvdaUq6gCrEZIbySFBM2T9DNKHg==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "@parcel/watcher", |  | ||||||
|         "chokidar", |  | ||||||
|         "immutable", |  | ||||||
|         "source-map-js" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "source-map-js@1.2.1": { |  | ||||||
|       "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" |  | ||||||
|     }, |  | ||||||
|     "to-regex-range@5.0.1": { |  | ||||||
|       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", |  | ||||||
|       "dependencies": [ |  | ||||||
|         "is-number" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     "undici-types@6.19.8": { |  | ||||||
|       "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   "workspace": { |  | ||||||
|     "packageJson": { |  | ||||||
|       "dependencies": [ |  | ||||||
|         "npm:js-yaml@^4.1.0", |  | ||||||
|         "npm:sass@^1.83.0" |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										25
									
								
								eslint.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								eslint.config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import js from "@eslint/js"; | ||||||
|  | import reactHooks from "eslint-plugin-react-hooks"; | ||||||
|  | import reactRefresh from "eslint-plugin-react-refresh"; | ||||||
|  | import globals from "globals"; | ||||||
|  | import tseslint from "typescript-eslint"; | ||||||
|  |  | ||||||
|  | export default tseslint.config( | ||||||
|  |   { ignores: ["dist"] }, | ||||||
|  |   { | ||||||
|  |     extends: [js.configs.recommended, ...tseslint.configs.recommended], | ||||||
|  |     files: ["**/*.{ts,tsx}"], | ||||||
|  |     languageOptions: { | ||||||
|  |       ecmaVersion: 2020, | ||||||
|  |       globals: globals.browser, | ||||||
|  |     }, | ||||||
|  |     plugins: { | ||||||
|  |       "react-hooks": reactHooks, | ||||||
|  |       "react-refresh": reactRefresh, | ||||||
|  |     }, | ||||||
|  |     rules: { | ||||||
|  |       ...reactHooks.configs.recommended.rules, | ||||||
|  |       "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | ); | ||||||
							
								
								
									
										59
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,10 +1,63 @@ | |||||||
| { | { | ||||||
|  |   "name": "gitea-github-theme", | ||||||
|  |   "version": "1.24.2", | ||||||
|  |   "description": "A theme to make Gitea look and feel like GitHub", | ||||||
|   "type": "module", |   "type": "module", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "build": "node build.js" |     "dev": "vite build --mode dev", | ||||||
|  |     "build": "tsc -b && vite build", | ||||||
|  |     "lint": "eslint .", | ||||||
|  |     "format": "prettier --write .", | ||||||
|  |     "commit": "npm run lint && npm run format && npm run build" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "js-yaml": "^4.1.0", |     "@babel/preset-react": "^7.27.1", | ||||||
|     "sass": "^1.83.0" |     "@babel/preset-typescript": "^7.27.1", | ||||||
|  |     "@eslint/js": "^9.29.0", | ||||||
|  |     "@linaria/core": "^6.3.0", | ||||||
|  |     "@linaria/react": "^6.3.0", | ||||||
|  |     "@types/node": "^24.0.3", | ||||||
|  |     "@types/react": "^19.1.8", | ||||||
|  |     "@types/react-dom": "^19.1.6", | ||||||
|  |     "@vanilla-extract/css": "^1.17.4", | ||||||
|  |     "@vanilla-extract/vite-plugin": "^5.0.6", | ||||||
|  |     "@vitejs/plugin-react": "^4.5.2", | ||||||
|  |     "@vitejs/plugin-react-swc": "^3.10.2", | ||||||
|  |     "@wyw-in-js/babel-preset": "^0.7.0", | ||||||
|  |     "@wyw-in-js/vite": "^0.7.0", | ||||||
|  |     "eslint": "^9.29.0", | ||||||
|  |     "eslint-plugin-react-hooks": "^5.2.0", | ||||||
|  |     "eslint-plugin-react-refresh": "^0.4.20", | ||||||
|  |     "globals": "^16.2.0", | ||||||
|  |     "lightningcss": "^1.30.1", | ||||||
|  |     "prettier": "3.5.3", | ||||||
|  |     "prettier-plugin-organize-imports": "^4.1.0", | ||||||
|  |     "react": "^19.1.0", | ||||||
|  |     "react-dom": "^19.1.0", | ||||||
|  |     "sass-embedded": "^1.89.2", | ||||||
|  |     "typescript": "^5.8.3", | ||||||
|  |     "typescript-eslint": "^8.34.1", | ||||||
|  |     "typescript-plugin-css-modules": "^5.1.0", | ||||||
|  |     "vite": "^6.3.5" | ||||||
|  |   }, | ||||||
|  |   "prettier": { | ||||||
|  |     "printWidth": 120, | ||||||
|  |     "tabWidth": 2, | ||||||
|  |     "useTabs": false, | ||||||
|  |     "semi": true, | ||||||
|  |     "singleQuote": false, | ||||||
|  |     "quoteProps": "as-needed", | ||||||
|  |     "jsxSingleQuote": false, | ||||||
|  |     "trailingComma": "es5", | ||||||
|  |     "bracketSpacing": true, | ||||||
|  |     "bracketSameLine": true, | ||||||
|  |     "arrowParens": "avoid", | ||||||
|  |     "proseWrap": "always", | ||||||
|  |     "htmlWhitespaceSensitivity": "css", | ||||||
|  |     "endOfLine": "lf", | ||||||
|  |     "plugins": [ | ||||||
|  |       "prettier-plugin-organize-imports" | ||||||
|  |     ], | ||||||
|  |     "organizeImportsSkipDestructiveCodeActions": false | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								src/color.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/color.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | import type { MapLeafNodes } from "src/types"; | ||||||
|  | import { color } from "src/vars"; | ||||||
|  |  | ||||||
|  | export type Primary = MapLeafNodes<typeof color.primary, string>; | ||||||
|  | export type Secondary = MapLeafNodes<typeof color.secondary, string>; | ||||||
							
								
								
									
										2
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | export * as color from "src/color"; | ||||||
|  | export { defineTheme, themeVars } from "src/theme"; | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| // Made by Luting ^-^ |  | ||||||
| .emoji[aria-label='check\\ mark'], |  | ||||||
| .emoji[aria-label='currency\\ exchange'], |  | ||||||
| .emoji[aria-label='TOP\\ arrow'], |  | ||||||
| .emoji[aria-label='END\\ arrow'], |  | ||||||
| .emoji[aria-label='ON! arrow'], |  | ||||||
| .emoji[aria-label='SOON\\ arrow'], |  | ||||||
| .emoji[aria-label='heavy dollar sign'], |  | ||||||
| .emoji[aria-label='copyright'], |  | ||||||
| .emoji[aria-label='registered'], |  | ||||||
| .emoji[aria-label='trade\\ mark'], |  | ||||||
| .emoji[aria-label='multiply'], |  | ||||||
| .emoji[aria-label='plus'], |  | ||||||
| .emoji[aria-label='minus'], |  | ||||||
| .emoji[aria-label='divide'], |  | ||||||
| .emoji[aria-label='curly\\ loop'], |  | ||||||
| .emoji[aria-label='double curly loop'], |  | ||||||
| .emoji[aria-label='wavy\\ dash'], |  | ||||||
| .emoji[aria-label='paw\\ prints'], |  | ||||||
| .emoji[aria-label='musical\\ note'], |  | ||||||
| .emoji[aria-label='musical\\ notes'] { |  | ||||||
|   filter: invert(100%) hue-rotate(180deg); |  | ||||||
| } |  | ||||||
							
								
								
									
										24
									
								
								src/theme.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/theme.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | import { createGlobalTheme, createGlobalThemeContract, globalStyle } from "@vanilla-extract/css"; | ||||||
|  | import type { MapLeafNodes, WithOptionalLayer } from "src/types"; | ||||||
|  | import { varMapper, vars } from "src/vars"; | ||||||
|  |  | ||||||
|  | function stringToBoolean(str: string, name: string): boolean { | ||||||
|  |   try { | ||||||
|  |     return JSON.parse(str); | ||||||
|  |   } catch (error) { | ||||||
|  |     console.error(error); | ||||||
|  |     throw new Error(`Invalid boolean value(${name}): ${str}`); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const themeVars = createGlobalThemeContract(vars, varMapper); | ||||||
|  | export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>; | ||||||
|  | export const defineTheme = (theme: Theme) => theme; | ||||||
|  |  | ||||||
|  | export function createTheme(theme: Theme): void { | ||||||
|  |   createGlobalTheme(":root", themeVars, theme); | ||||||
|  |   globalStyle(":root", { | ||||||
|  |     accentColor: themeVars.color.blue, | ||||||
|  |     colorScheme: stringToBoolean(theme.isDarkTheme, "isDarkTheme") ? "dark" : "light", | ||||||
|  |   }); | ||||||
|  | } | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| // Made by Luting ^-^ |  | ||||||
| @use "dark/github-dark.css"; // GitHub 变量(仅主题内部使用的变量) |  | ||||||
| @use "dark/gitea-dark.css"; // Gitea 变量(元素默认使用的变量) |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| /* Made by Luting ^-^ */ |  | ||||||
							
								
								
									
										12
									
								
								src/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/types.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | type Primitive = string | boolean | number | null | undefined; | ||||||
|  | type Tokens = { [key: string]: string | Tokens }; | ||||||
|  |  | ||||||
|  | export type WithOptionalLayer<T extends Tokens> = T & { "@layer"?: string }; | ||||||
|  |  | ||||||
|  | export type MapLeafNodes<Obj, LeafType> = { | ||||||
|  |   [Prop in keyof Obj]: Obj[Prop] extends Primitive | ||||||
|  |     ? LeafType | ||||||
|  |     : Obj[Prop] extends Record<string | number, unknown> | ||||||
|  |       ? MapLeafNodes<Obj[Prop], LeafType> | ||||||
|  |       : never; | ||||||
|  | }; | ||||||
							
								
								
									
										69
									
								
								src/vars/color.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/vars/color.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | const num = { | ||||||
|  |   1: null, | ||||||
|  |   2: null, | ||||||
|  |   3: null, | ||||||
|  |   4: null, | ||||||
|  |   5: null, | ||||||
|  |   6: null, | ||||||
|  |   7: null, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const alpha = { | ||||||
|  |   10: null, | ||||||
|  |   20: null, | ||||||
|  |   30: null, | ||||||
|  |   40: null, | ||||||
|  |   50: null, | ||||||
|  |   60: null, | ||||||
|  |   70: null, | ||||||
|  |   80: null, | ||||||
|  |   90: null, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const primary = { | ||||||
|  |   self: null, | ||||||
|  |   contrast: null, | ||||||
|  |   dark: num, | ||||||
|  |   light: num, | ||||||
|  |   alpha: alpha, | ||||||
|  |   hover: null, | ||||||
|  |   active: null, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const secondary = { | ||||||
|  |   self: null, | ||||||
|  |   dark: { | ||||||
|  |     8: null, | ||||||
|  |     9: null, | ||||||
|  |     10: null, | ||||||
|  |     11: null, | ||||||
|  |     12: null, | ||||||
|  |     13: null, | ||||||
|  |     ...num, | ||||||
|  |   }, | ||||||
|  |   light: { | ||||||
|  |     1: null, | ||||||
|  |     2: null, | ||||||
|  |     3: null, | ||||||
|  |     4: null, | ||||||
|  |   }, | ||||||
|  |   alpha: alpha, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const color = { | ||||||
|  |   red: null, | ||||||
|  |   orange: null, | ||||||
|  |   yellow: null, | ||||||
|  |   olive: null, | ||||||
|  |   green: null, | ||||||
|  |   teal: null, | ||||||
|  |   blue: null, | ||||||
|  |   violet: null, | ||||||
|  |   purple: null, | ||||||
|  |   pink: null, | ||||||
|  |   brown: null, | ||||||
|  |   black: null, | ||||||
|  |   grey: null, | ||||||
|  |   gold: null, | ||||||
|  |   white: null, | ||||||
|  | }; | ||||||
							
								
								
									
										20
									
								
								src/vars/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/vars/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | import * as color from "src/vars/color"; | ||||||
|  |  | ||||||
|  | export function varMapper(value: string | null, path: string[]) { | ||||||
|  |   if (value === null) { | ||||||
|  |     if (path.at(-1) === "self") return path.slice(0, -1).join("-"); | ||||||
|  |     return path.join("-"); | ||||||
|  |   } | ||||||
|  |   return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const vars = { | ||||||
|  |   /** 用于标识当前是否为暗色主题: `"true"` 暗色 `"false"` 亮色 */ | ||||||
|  |   isDarkTheme: "is-dark-theme", | ||||||
|  |   color: { | ||||||
|  |     blue: null, | ||||||
|  |     primary: color.primary, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export { color }; | ||||||
							
								
								
									
										77
									
								
								src/vite.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/vite.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | import fs from "fs"; | ||||||
|  | import path from "path"; | ||||||
|  | import type { Plugin } from "vite"; | ||||||
|  |  | ||||||
|  | export function themeInput( | ||||||
|  |   outDir: string, | ||||||
|  |   themeDir: string, | ||||||
|  |   devTheme: string, | ||||||
|  |   mode: string | ||||||
|  | ): { [key: string]: string } { | ||||||
|  |   const tmpDir = `${outDir}/tmp`; // 输出目录下的临时目录 | ||||||
|  |   fs.mkdirSync(tmpDir, { recursive: true }); | ||||||
|  |  | ||||||
|  |   const input: { [key: string]: string } = {}; | ||||||
|  |   const themeEntries = fs.readdirSync(themeDir, { withFileTypes: true }); | ||||||
|  |  | ||||||
|  |   for (const entry of themeEntries) { | ||||||
|  |     // 目录下所有的 css.ts 文件都作为主题入口 | ||||||
|  |     if (entry.isFile() && entry.name.endsWith(".css.ts")) { | ||||||
|  |       const fileName = entry.name.replace(".css.ts", ""); | ||||||
|  |       // 开发模式只打包 devTheme 主题 | ||||||
|  |       if (mode === "dev" && fileName !== devTheme) continue; | ||||||
|  |       // 创建颜色主题的 css.ts 文件, vanilla-extract 需要这个文件后缀名并生成 css | ||||||
|  |       const tmpCssTs = path.join(tmpDir, `${fileName}.css.ts`); | ||||||
|  |       const createImport = `import { createTheme } from "src/theme";`; | ||||||
|  |       const themeImport = `import theme from "themes/${fileName}";`; | ||||||
|  |       const createFn = `createTheme(theme);`; | ||||||
|  |       fs.writeFileSync(tmpCssTs, `${createImport}\n${themeImport}\n${createFn}`); | ||||||
|  |       // 生成主题入口的 .ts 文件, 合并样式和颜色主题 | ||||||
|  |       const tmpInputTs = path.join(tmpDir, `${fileName}.ts`); | ||||||
|  |       const stylesImport = `import "styles";`; | ||||||
|  |       const cssImport = `import "./${fileName}.css.ts";`; | ||||||
|  |       fs.writeFileSync(tmpInputTs, `${stylesImport}\n${cssImport}`); | ||||||
|  |  | ||||||
|  |       input[fileName] = tmpInputTs; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return input; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const prefix = "theme-github-"; | ||||||
|  |  | ||||||
|  | export function themePlugin(): Plugin { | ||||||
|  |   return { | ||||||
|  |     name: "themePlugin", | ||||||
|  |     generateBundle(this, _, bundle) { | ||||||
|  |       let styles = ""; | ||||||
|  |       for (const [key, value] of Object.entries(bundle)) { | ||||||
|  |         if (value.type === "chunk") { | ||||||
|  |           delete bundle[key]; // 删除 chunk | ||||||
|  |         } else { | ||||||
|  |           // 样式文件是通过入口导入的, 没有原始文件名 | ||||||
|  |           if (value.originalFileNames.length === 0) { | ||||||
|  |             // 收集所有的样式文件(逻辑上只有一个) | ||||||
|  |             // vite 会在尾部添加注释, 后续会合并到颜色主题, 此处需要删除注释 | ||||||
|  |             styles += value.source.toString().replace("/*$vite$:1*/", ""); | ||||||
|  |             delete bundle[key]; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       // 生成所有的主题文件 | ||||||
|  |       for (const [key, value] of Object.entries(bundle)) { | ||||||
|  |         // 仅为了类型检查, 逻辑上输出中全是 asset 类型 | ||||||
|  |         if (value.type === "asset") { | ||||||
|  |           const name = `${prefix}${value.names[0]}`; | ||||||
|  |           const fileName = `${prefix}${value.fileName}`; | ||||||
|  |           const originalFileName = value.originalFileNames.pop(); | ||||||
|  |           const type = value.type; | ||||||
|  |           const source = `${styles}${value.source.toString()}`; | ||||||
|  |           // 添加主题到输出 | ||||||
|  |           this.emitFile({ name, fileName, source, type, originalFileName }); | ||||||
|  |           delete bundle[key]; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | } | ||||||
| @@ -4,4 +4,4 @@ | |||||||
|     height: 18px; |     height: 18px; | ||||||
|     width: 18px; |     width: 18px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -18,33 +18,33 @@ | |||||||
| 
 | 
 | ||||||
| .vch__day__square, | .vch__day__square, | ||||||
| .vch__legend__wrapper rect { | .vch__legend__wrapper rect { | ||||||
|   &[style='fill: var(--color-secondary-alpha-60);'] { |   &[style="fill: var(--color-secondary-alpha-60);"] { | ||||||
|     outline: 1px solid rgba(27, 31, 35, 0.06); |     outline: 1px solid rgba(27, 31, 35, 0.06); | ||||||
|     background: #161b22; |     background: #161b22; | ||||||
|     fill: #161b22 !important; |     fill: #161b22 !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &[style='fill: var(--color-primary-light-4);'] { |   &[style="fill: var(--color-primary-light-4);"] { | ||||||
|     background: #0e4429; |     background: #0e4429; | ||||||
|     fill: #0e4429 !important; |     fill: #0e4429 !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &[style='fill: var(--color-primary-light-2);'] { |   &[style="fill: var(--color-primary-light-2);"] { | ||||||
|     background: #006d32; |     background: #006d32; | ||||||
|     fill: #006d32 !important; |     fill: #006d32 !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &[style='fill: var(--color-primary);'] { |   &[style="fill: var(--color-primary);"] { | ||||||
|     background: #238636; |     background: #238636; | ||||||
|     fill: #238636 !important; |     fill: #238636 !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &[style='fill: var(--color-primary-dark-2);'] { |   &[style="fill: var(--color-primary-dark-2);"] { | ||||||
|     background: #39d353; |     background: #39d353; | ||||||
|     fill: #39d353 !important; |     fill: #39d353 !important; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   &[style='fill: var(--color-primary-dark-4);'] { |   &[style="fill: var(--color-primary-dark-4);"] { | ||||||
|     background: #44ff61; |     background: #44ff61; | ||||||
|     fill: #44ff61 !important; |     fill: #44ff61 !important; | ||||||
|   } |   } | ||||||
| @@ -4,7 +4,7 @@ | |||||||
| %active-item-after-style { | %active-item-after-style { | ||||||
|   background: #1f6feb; |   background: #1f6feb; | ||||||
|   border-radius: 0.375rem; |   border-radius: 0.375rem; | ||||||
|   content: ''; |   content: ""; | ||||||
|   height: 24px; |   height: 24px; | ||||||
|   left: calc(0.5rem * -1); |   left: calc(0.5rem * -1); | ||||||
|   position: absolute; |   position: absolute; | ||||||
| @@ -134,17 +134,17 @@ | |||||||
|   .ui.form input:not([type]), |   .ui.form input:not([type]), | ||||||
|   .ui.form select, |   .ui.form select, | ||||||
|   .ui.form textarea, |   .ui.form textarea, | ||||||
|   .ui.form input[type='date'], |   .ui.form input[type="date"], | ||||||
|   .ui.form input[type='datetime-local'], |   .ui.form input[type="datetime-local"], | ||||||
|   .ui.form input[type='email'], |   .ui.form input[type="email"], | ||||||
|   .ui.form input[type='file'], |   .ui.form input[type="file"], | ||||||
|   .ui.form input[type='number'], |   .ui.form input[type="number"], | ||||||
|   .ui.form input[type='password'], |   .ui.form input[type="password"], | ||||||
|   .ui.form input[type='search'], |   .ui.form input[type="search"], | ||||||
|   .ui.form input[type='tel'], |   .ui.form input[type="tel"], | ||||||
|   .ui.form input[type='text'], |   .ui.form input[type="text"], | ||||||
|   .ui.form input[type='time'], |   .ui.form input[type="time"], | ||||||
|   .ui.form input[type='url'], |   .ui.form input[type="url"], | ||||||
|   .ui.selection.dropdown { |   .ui.selection.dropdown { | ||||||
|     background: var(--color-box-header); |     background: var(--color-box-header); | ||||||
|   } |   } | ||||||
| @@ -152,17 +152,17 @@ | |||||||
|   .ui.form input:not([type]), |   .ui.form input:not([type]), | ||||||
|   .ui.form select, |   .ui.form select, | ||||||
|   .ui.form textarea, |   .ui.form textarea, | ||||||
|   .ui.form input[type='date'], |   .ui.form input[type="date"], | ||||||
|   .ui.form input[type='datetime-local'], |   .ui.form input[type="datetime-local"], | ||||||
|   .ui.form input[type='email'], |   .ui.form input[type="email"], | ||||||
|   .ui.form input[type='file'], |   .ui.form input[type="file"], | ||||||
|   .ui.form input[type='number'], |   .ui.form input[type="number"], | ||||||
|   .ui.form input[type='password'], |   .ui.form input[type="password"], | ||||||
|   .ui.form input[type='search'], |   .ui.form input[type="search"], | ||||||
|   .ui.form input[type='tel'], |   .ui.form input[type="tel"], | ||||||
|   .ui.form input[type='text'], |   .ui.form input[type="text"], | ||||||
|   .ui.form input[type='time'], |   .ui.form input[type="time"], | ||||||
|   .ui.form input[type='url'] { |   .ui.form input[type="url"] { | ||||||
|     padding: 7px 12px; |     padding: 7px 12px; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
							
								
								
									
										1
									
								
								styles/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								styles/index.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | import "styles/test"; | ||||||
| @@ -22,7 +22,10 @@ | |||||||
|   background: var(--color-box-header); |   background: var(--color-box-header); | ||||||
|   border-radius: 12px; |   border-radius: 12px; | ||||||
|   overflow: hidden; |   overflow: hidden; | ||||||
|   box-shadow: 0px 0px 0px 0.5px #30363d, 0px 6px 12px -3px rgba(1, 4, 9, 0.4), 0px 6px 18px 0px rgba(1, 4, 9, 0.4); |   box-shadow: | ||||||
|  |     0px 0px 0px 0.5px #30363d, | ||||||
|  |     0px 6px 12px -3px rgba(1, 4, 9, 0.4), | ||||||
|  |     0px 6px 18px 0px rgba(1, 4, 9, 0.4); | ||||||
|   animation: 200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running overlay-appear; |   animation: 200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running overlay-appear; | ||||||
| 
 | 
 | ||||||
|   .clone-panel-field { |   .clone-panel-field { | ||||||
| @@ -50,7 +53,7 @@ | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       &.active:after { |       &.active:after { | ||||||
|         content: ''; |         content: ""; | ||||||
|         display: block; |         display: block; | ||||||
|         position: absolute; |         position: absolute; | ||||||
|         bottom: -8px; |         bottom: -8px; | ||||||
| @@ -96,10 +99,13 @@ | |||||||
|   margin-top: 3.75px !important; |   margin-top: 3.75px !important; | ||||||
|   border-radius: 12px !important; |   border-radius: 12px !important; | ||||||
|   overflow: hidden auto; |   overflow: hidden auto; | ||||||
|   box-shadow: 0px 0px 0px 0.5px #30363d, 0px 6px 12px -3px #01040966, 0px 6px 18px 0px #01040966; |   box-shadow: | ||||||
|  |     0px 0px 0px 0.5px #30363d, | ||||||
|  |     0px 6px 12px -3px #01040966, | ||||||
|  |     0px 6px 18px 0px #01040966; | ||||||
|   animation: 200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running overlay-appear; |   animation: 200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running overlay-appear; | ||||||
| 
 | 
 | ||||||
|   >.item { |   > .item { | ||||||
|     padding: 8px 10px !important; |     padding: 8px 10px !important; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -181,7 +187,7 @@ | |||||||
| 
 | 
 | ||||||
|     // 分支菜单下划线 |     // 分支菜单下划线 | ||||||
|     &:before { |     &:before { | ||||||
|       content: ' '; |       content: " "; | ||||||
|       display: block; |       display: block; | ||||||
|       position: absolute; |       position: absolute; | ||||||
|       width: 100%; |       width: 100%; | ||||||
							
								
								
									
										23
									
								
								styles/public/emoji.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								styles/public/emoji.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | // Made by Luting ^-^ | ||||||
|  | .emoji[aria-label="check\\ mark"], | ||||||
|  | .emoji[aria-label="currency\\ exchange"], | ||||||
|  | .emoji[aria-label="TOP\\ arrow"], | ||||||
|  | .emoji[aria-label="END\\ arrow"], | ||||||
|  | .emoji[aria-label="ON! arrow"], | ||||||
|  | .emoji[aria-label="SOON\\ arrow"], | ||||||
|  | .emoji[aria-label="heavy dollar sign"], | ||||||
|  | .emoji[aria-label="copyright"], | ||||||
|  | .emoji[aria-label="registered"], | ||||||
|  | .emoji[aria-label="trade\\ mark"], | ||||||
|  | .emoji[aria-label="multiply"], | ||||||
|  | .emoji[aria-label="plus"], | ||||||
|  | .emoji[aria-label="minus"], | ||||||
|  | .emoji[aria-label="divide"], | ||||||
|  | .emoji[aria-label="curly\\ loop"], | ||||||
|  | .emoji[aria-label="double curly loop"], | ||||||
|  | .emoji[aria-label="wavy\\ dash"], | ||||||
|  | .emoji[aria-label="paw\\ prints"], | ||||||
|  | .emoji[aria-label="musical\\ note"], | ||||||
|  | .emoji[aria-label="musical\\ notes"] { | ||||||
|  |   filter: invert(100%) hue-rotate(180deg); | ||||||
|  | } | ||||||
| @@ -5,17 +5,17 @@ textarea, | |||||||
| .ui.form input:not([type]), | .ui.form input:not([type]), | ||||||
| .ui.form select, | .ui.form select, | ||||||
| .ui.form textarea, | .ui.form textarea, | ||||||
| .ui.form input[type='date'], | .ui.form input[type="date"], | ||||||
| .ui.form input[type='datetime-local'], | .ui.form input[type="datetime-local"], | ||||||
| .ui.form input[type='email'], | .ui.form input[type="email"], | ||||||
| .ui.form input[type='file'], | .ui.form input[type="file"], | ||||||
| .ui.form input[type='number'], | .ui.form input[type="number"], | ||||||
| .ui.form input[type='password'], | .ui.form input[type="password"], | ||||||
| .ui.form input[type='search'], | .ui.form input[type="search"], | ||||||
| .ui.form input[type='tel'], | .ui.form input[type="tel"], | ||||||
| .ui.form input[type='text'], | .ui.form input[type="text"], | ||||||
| .ui.form input[type='time'], | .ui.form input[type="time"], | ||||||
| .ui.form input[type='url'], | .ui.form input[type="url"], | ||||||
| .ui.selection.dropdown { | .ui.selection.dropdown { | ||||||
|   background: unset; |   background: unset; | ||||||
| 
 | 
 | ||||||
| @@ -25,17 +25,17 @@ | |||||||
|   .ui.form input:not([type]), |   .ui.form input:not([type]), | ||||||
|   .ui.form select, |   .ui.form select, | ||||||
|   .ui.form textarea, |   .ui.form textarea, | ||||||
|   .ui.form input[type='date'], |   .ui.form input[type="date"], | ||||||
|   .ui.form input[type='datetime-local'], |   .ui.form input[type="datetime-local"], | ||||||
|   .ui.form input[type='email'], |   .ui.form input[type="email"], | ||||||
|   .ui.form input[type='file'], |   .ui.form input[type="file"], | ||||||
|   .ui.form input[type='number'], |   .ui.form input[type="number"], | ||||||
|   .ui.form input[type='password'], |   .ui.form input[type="password"], | ||||||
|   .ui.form input[type='search'], |   .ui.form input[type="search"], | ||||||
|   .ui.form input[type='tel'], |   .ui.form input[type="tel"], | ||||||
|   .ui.form input[type='text'], |   .ui.form input[type="text"], | ||||||
|   .ui.form input[type='time'], |   .ui.form input[type="time"], | ||||||
|   .ui.form input[type='url'], |   .ui.form input[type="url"], | ||||||
|   .ui.selection.dropdown { |   .ui.selection.dropdown { | ||||||
|     &:focus, |     &:focus, | ||||||
|     &:focus-visible { |     &:focus-visible { | ||||||
| @@ -1,21 +1,20 @@ | |||||||
| // Made by Luting ^-^ |  | ||||||
| .ui { | .ui { | ||||||
|   &.button, |   &.button, | ||||||
|   &.basic.buttons .button, |   &.basic.buttons .button, | ||||||
|   &.basic.button, |   &.basic.button, | ||||||
|   &.dropdown .menu, |   &.dropdown .menu, | ||||||
|   &.form input:not([type]), |   &.form input:not([type]), | ||||||
|   &.form input[type='date'], |   &.form input[type="date"], | ||||||
|   &.form input[type='datetime-local'], |   &.form input[type="datetime-local"], | ||||||
|   &.form input[type='email'], |   &.form input[type="email"], | ||||||
|   &.form input[type='number'], |   &.form input[type="number"], | ||||||
|   &.form input[type='password'], |   &.form input[type="password"], | ||||||
|   &.form input[type='search'], |   &.form input[type="search"], | ||||||
|   &.form input[type='tel'], |   &.form input[type="tel"], | ||||||
|   &.form input[type='time'], |   &.form input[type="time"], | ||||||
|   &.form input[type='text'], |   &.form input[type="text"], | ||||||
|   &.form input[type='file'], |   &.form input[type="file"], | ||||||
|   &.form input[type='url'], |   &.form input[type="url"], | ||||||
|   &.form textarea, |   &.form textarea, | ||||||
|   &.input textarea, |   &.input textarea, | ||||||
|   &.ui.input > input, |   &.ui.input > input, | ||||||
| @@ -42,7 +41,7 @@ | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 左边框圆角 | /* 左边框圆角 */ | ||||||
| .ui { | .ui { | ||||||
|   &.action.input > .dropdown:first-child, |   &.action.input > .dropdown:first-child, | ||||||
|   &.action.input > .button:first-child, |   &.action.input > .button:first-child, | ||||||
| @@ -53,7 +52,7 @@ | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 右边框圆角 | /* 右边框圆角 */ | ||||||
| .ui { | .ui { | ||||||
|   &.action.input > .dropdown:last-child, |   &.action.input > .dropdown:last-child, | ||||||
|   &.action.input > .button:last-child, |   &.action.input > .button:last-child, | ||||||
| @@ -64,7 +63,7 @@ | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 上边框圆角 | /* 上边框圆角 */ | ||||||
| .ui.secondary.pointing.menu { | .ui.secondary.pointing.menu { | ||||||
|   .active.item, |   .active.item, | ||||||
|   .item:hover { |   .item:hover { | ||||||
| @@ -78,13 +77,13 @@ | |||||||
|   border-top-right-radius: var(--border-radius) !important; |   border-top-right-radius: var(--border-radius) !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 按钮边框圆角 | /* 按钮边框圆角 */ | ||||||
| .ui.active.selection.dropdown { | .ui.active.selection.dropdown { | ||||||
|   border-bottom-left-radius: var(--border-radius) !important; |   border-bottom-left-radius: var(--border-radius) !important; | ||||||
|   border-bottom-right-radius: var(--border-radius) !important; |   border-bottom-right-radius: var(--border-radius) !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .ui.segment[class*='bottom attached'] { | .ui.segment[class*="bottom attached"] { | ||||||
|   border-radius: 0 0 var(--border-radius) var(--border-radius); |   border-radius: 0 0 var(--border-radius) var(--border-radius); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| // Made by Luting ^-^ |  | ||||||
| .text { | .text { | ||||||
|   .purple { |   .purple { | ||||||
|     color: #ab7df8 !important; |     color: #ab7df8 !important; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   .green { |   .green { | ||||||
|     color: #3fb950 !important; |     color: #3fb950 !important; | ||||||
|   } |   } | ||||||
| @@ -24,7 +24,7 @@ | |||||||
| .ui.selection.dropdown, | .ui.selection.dropdown, | ||||||
| .ui.checkbox label:before, | .ui.checkbox label:before, | ||||||
| .ui.checkbox input:checked ~ label:before, | .ui.checkbox input:checked ~ label:before, | ||||||
| .ui.checkbox input:not([type='radio']):indeterminate ~ label:before, | .ui.checkbox input:not([type="radio"]):indeterminate ~ label:before, | ||||||
| .ui.selection.active.dropdown, | .ui.selection.active.dropdown, | ||||||
| .ui.selection.active.dropdown:hover, | .ui.selection.active.dropdown:hover, | ||||||
| .ui.selection.active.dropdown .menu, | .ui.selection.active.dropdown .menu, | ||||||
| @@ -42,4 +42,4 @@ textarea, | |||||||
| .job-step-logs, | .job-step-logs, | ||||||
| .job-brief-item { | .job-brief-item { | ||||||
|   animation: 200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running overlay-appear; |   animation: 200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running overlay-appear; | ||||||
| } | } | ||||||
							
								
								
									
										23
									
								
								styles/test.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								styles/test.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import { css } from "@linaria/core"; | ||||||
|  | import { themeVars } from "src/theme"; | ||||||
|  |  | ||||||
|  | export const setting_global = css` | ||||||
|  |   :global() { | ||||||
|  |     .user-main-content, | ||||||
|  |     .repo-setting-content, | ||||||
|  |     .user-setting-content, | ||||||
|  |     .org-setting-content, | ||||||
|  |     .admin-setting-content { | ||||||
|  |       .ui.right { | ||||||
|  |         .ui.primary.button.tiny { | ||||||
|  |           color: #fff; | ||||||
|  |           background-color: #238636; | ||||||
|  |           &:hover { | ||||||
|  |             background-color: #29903b; | ||||||
|  |             border-color: ${themeVars.color.primary.light[1]}; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | `; | ||||||
							
								
								
									
										13
									
								
								themes/dark-pink.css.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								themes/dark-pink.css.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import { defineTheme } from "src"; | ||||||
|  | import dark_theme from "themes/dark"; | ||||||
|  |  | ||||||
|  | export default defineTheme({ | ||||||
|  |   ...dark_theme, | ||||||
|  |   color: { | ||||||
|  |     ...dark_theme.color, | ||||||
|  |     primary: { | ||||||
|  |       ...dark_theme.color.primary, | ||||||
|  |       hover: "pink", | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }); | ||||||
							
								
								
									
										52
									
								
								themes/dark.css.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								themes/dark.css.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | import type { color } from "src"; | ||||||
|  | import { defineTheme, themeVars } from "src"; | ||||||
|  |  | ||||||
|  | const dark = { | ||||||
|  |   1: "#739cb3", | ||||||
|  |   2: "#40aaff", | ||||||
|  |   3: "#92b4c4", | ||||||
|  |   4: "#a1bbcd", | ||||||
|  |   5: "#cfddc1", | ||||||
|  |   6: "#e7eee0", | ||||||
|  |   7: "#f8faf6", | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const light = { | ||||||
|  |   1: themeVars.color.blue, | ||||||
|  |   2: "#437aad", | ||||||
|  |   3: "#415b8b", | ||||||
|  |   4: "#25425a", | ||||||
|  |   5: "#223546", | ||||||
|  |   6: "#131923", | ||||||
|  |   7: "#06090b", | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const alpha = { | ||||||
|  |   10: "#3683c019", | ||||||
|  |   20: "#3683c033", | ||||||
|  |   30: "#3683c04b", | ||||||
|  |   40: "#3683c066", | ||||||
|  |   50: "#3683c080", | ||||||
|  |   60: "#3683c099", | ||||||
|  |   70: "#3683c0b3", | ||||||
|  |   80: "#3683c0cc", | ||||||
|  |   90: "#3683c0e1", | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const primary: color.Primary = { | ||||||
|  |   self: themeVars.color.blue, | ||||||
|  |   contrast: "#fff", | ||||||
|  |   dark, | ||||||
|  |   light, | ||||||
|  |   alpha, | ||||||
|  |   hover: light[1], | ||||||
|  |   active: light[2], | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default defineTheme({ | ||||||
|  |   isDarkTheme: "true", | ||||||
|  |   color: { | ||||||
|  |     blue: "blue", | ||||||
|  |     primary: primary, | ||||||
|  |   }, | ||||||
|  | }); | ||||||
| @@ -251,4 +251,4 @@ | |||||||
|   --color-active-line: #534d1b; |   --color-active-line: #534d1b; | ||||||
|   accent-color: var(--color-accent); |   accent-color: var(--color-accent); | ||||||
|   color-scheme: dark; |   color-scheme: dark; | ||||||
| } | } | ||||||
							
								
								
									
										38
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | { | ||||||
|  |   "compilerOptions": { | ||||||
|  |     "plugins": [ | ||||||
|  |       { | ||||||
|  |         "name": "typescript-plugin-css-modules" | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", | ||||||
|  |     "useDefineForClassFields": true, | ||||||
|  |     "target": "ES2022", | ||||||
|  |     "lib": ["ES2023"], | ||||||
|  |     "module": "ESNext", | ||||||
|  |     "skipLibCheck": true, | ||||||
|  |  | ||||||
|  |     /* Bundler mode */ | ||||||
|  |     "moduleResolution": "bundler", | ||||||
|  |     "allowImportingTsExtensions": true, | ||||||
|  |     "verbatimModuleSyntax": true, | ||||||
|  |     "moduleDetection": "force", | ||||||
|  |     "noEmit": true, | ||||||
|  |     "jsx": "react-jsx", | ||||||
|  |  | ||||||
|  |     /* Linting */ | ||||||
|  |     "strict": true, | ||||||
|  |     "noUnusedLocals": true, | ||||||
|  |     "noUnusedParameters": true, | ||||||
|  |     "erasableSyntaxOnly": true, | ||||||
|  |     "noFallthroughCasesInSwitch": true, | ||||||
|  |     "noUncheckedSideEffectImports": true, | ||||||
|  |     "baseUrl": ".", | ||||||
|  |     "paths": { | ||||||
|  |       "src/*": ["src/*"], | ||||||
|  |       "styles/*": ["styles/*"], | ||||||
|  |       "themes/*": ["themes/*", "themes/*.css"] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "include": ["src", "styles", "themes", "vite.config.ts"] | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin"; | ||||||
|  | import react from "@vitejs/plugin-react"; | ||||||
|  | import linaria from "@wyw-in-js/vite"; | ||||||
|  | import { Features } from "lightningcss"; | ||||||
|  | import path from "path"; | ||||||
|  | import { defineConfig } from "vite"; | ||||||
|  | import { themeInput, themePlugin } from "./src/vite"; | ||||||
|  |  | ||||||
|  | const devTheme = "dark"; // 开发模式仅打包单个颜色主题 | ||||||
|  | const outDir = "dist"; // 输出目录 | ||||||
|  | const themesDir = "themes"; // 颜色主题目录 | ||||||
|  |  | ||||||
|  | export default defineConfig(({ mode }) => { | ||||||
|  |   return { | ||||||
|  |     resolve: { | ||||||
|  |       alias: { | ||||||
|  |         src: path.resolve(__dirname, "src"), | ||||||
|  |         styles: path.resolve(__dirname, "styles"), | ||||||
|  |         themes: path.resolve(__dirname, "themes"), | ||||||
|  |       }, | ||||||
|  |       extensions: [".js", ".jsx", ".ts", ".tsx", ".css.ts"], | ||||||
|  |     }, | ||||||
|  |     css: { | ||||||
|  |       transformer: "lightningcss", | ||||||
|  |       lightningcss: { | ||||||
|  |         minify: true, | ||||||
|  |         exclude: Features.LightDark, // 不生成 lightningcss 的主题变量 | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     plugins: [ | ||||||
|  |       linaria({ | ||||||
|  |         include: ["**/*.{ts,tsx}"], | ||||||
|  |         babelOptions: { | ||||||
|  |           presets: ["@babel/preset-typescript", "@babel/preset-react"], | ||||||
|  |         }, | ||||||
|  |       }), | ||||||
|  |       react(), | ||||||
|  |       vanillaExtractPlugin(), | ||||||
|  |       themePlugin(), | ||||||
|  |     ], | ||||||
|  |     build: { | ||||||
|  |       cssMinify: "lightningcss", | ||||||
|  |       cssCodeSplit: true, | ||||||
|  |       outDir: outDir, | ||||||
|  |       rollupOptions: { | ||||||
|  |         input: themeInput(outDir, themesDir, devTheme, mode), | ||||||
|  |         output: { | ||||||
|  |           assetFileNames: "[name].[ext]", | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | }); | ||||||
		Reference in New Issue
	
	Block a user