├── .browserslistrc
├── .env
├── .eslintrc.js
├── .github
└── workflows
│ ├── build.yml
│ └── docker-build-push.yml
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── babel.config.js
├── package.json
├── public
├── _redirects
├── favicon.ico
├── img
│ └── icons
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── android-chrome-maskable-192x192.png
│ │ ├── android-chrome-maskable-512x512.png
│ │ ├── apple-touch-icon-120x120.png
│ │ ├── apple-touch-icon-152x152.png
│ │ ├── apple-touch-icon-180x180.png
│ │ ├── apple-touch-icon-60x60.png
│ │ ├── apple-touch-icon-76x76.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── msapplication-icon-144x144.png
│ │ ├── mstile-150x150.png
│ │ └── safari-pinned-tab.svg
├── index.html
├── manifest.json
└── robots.txt
├── services
├── .env
├── .gitignore
├── data
│ └── .gitkeep
└── docker-compose.yaml
├── src
├── App.vue
├── assets
│ ├── css
│ │ ├── element-ui.scss
│ │ └── element-variables.scss
│ └── logo.png
├── components
│ └── SvgIcon
│ │ └── index.vue
├── icons
│ ├── index.js
│ └── svg
│ │ └── github.svg
├── main.js
├── plugins
│ ├── axios.js
│ ├── base64.js
│ ├── clipboard.js
│ ├── device.js
│ ├── element-ui.js
│ └── particles.js
├── registerServiceWorker.js
├── router
│ └── index.js
└── views
│ └── Subconverter.vue
├── vue.config.js
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_PROJECT = "https://github.com/CareyWang/sub-web"
2 |
3 | VUE_APP_BOT_LINK = "https://t.me/subconverter_discuss"
4 |
5 | VUE_APP_BACKEND_RELEASE = "https://github.com/tindy2013/subconverter/actions"
6 |
7 | VUE_APP_SUBCONVERTER_REMOTE_CONFIG = "https://raw.githubusercontent.com/tindy2013/subconverter/master/base/config/example_external_config.ini"
8 |
9 | VUE_APP_SUBCONVERTER_DOC_ADVANCED = "https://github.com/tindy2013/subconverter/blob/master/README-cn.md#%E8%BF%9B%E9%98%B6%E9%93%BE%E6%8E%A5"
10 |
11 | # API 后端
12 | VUE_APP_SUBCONVERTER_DEFAULT_BACKEND = "https://api.wcc.best"
13 |
14 | # 短链接后端
15 | VUE_APP_MYURLS_API = "https://suo.yt/short"
16 |
17 | # 文本托管后端
18 | VUE_APP_CONFIG_UPLOAD_API = "https://oss.wcc.best/upload"
19 |
20 | # 页面配置
21 | VUE_APP_USE_STORAGE = true
22 | VUE_APP_CACHE_TTL = 86400
23 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | 'eslint:recommended'
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'semi': 0,
14 | 'vue/multi-word-component-names': 'off'
15 | },
16 | parserOptions: {
17 | parser: '@babel/eslint-parser'
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: [ master, dev ]
6 |
7 | jobs:
8 |
9 | build:
10 | name: Build
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [20.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 |
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 |
25 | - name: Get dependencies and build
26 | run: |
27 | yarn install
28 | yarn build
29 |
30 | - name: Upload
31 | uses: actions/upload-artifact@v4
32 | with:
33 | name: dist
34 | path: dist/
35 |
--------------------------------------------------------------------------------
/.github/workflows/docker-build-push.yml:
--------------------------------------------------------------------------------
1 | name: Build and Push Multi-Arch Docker Image
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build-and-push:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - name: Check out repository
14 | uses: actions/checkout@master
15 |
16 | - name: Set up Docker Buildx
17 | uses: docker/setup-buildx-action@v2
18 |
19 | - name: Log in to Docker Hub
20 | uses: docker/login-action@v2
21 | with:
22 | username: ${{ secrets.DOCKERHUB_USERNAME }}
23 | password: ${{ secrets.DOCKERHUB_PASSWORD }}
24 |
25 | - name: Build and push Docker image
26 | uses: docker/build-push-action@v3
27 | with:
28 | context: .
29 | platforms: linux/amd64,linux/arm64
30 | push: true
31 | tags: careywong/subweb:latest
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # ---- Dependencies ----
2 | FROM node:20-alpine AS build
3 | WORKDIR /app
4 | COPY . .
5 | RUN yarn install
6 | RUN yarn build
7 |
8 | FROM nginx:1.24-alpine
9 | COPY --from=build /app/dist /usr/share/nginx/html
10 | EXPOSE 80
11 | CMD [ "nginx", "-g", "daemon off;" ]
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 CareyWong
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sub-web
2 |
3 | 基于 vue-cli 与 [tindy2013/subconverter](https://github.com/tindy2013/subconverter) 后端实现的配置自动生成。
4 |
5 | ## Table of Contents
6 |
7 | - [ChangeLog](#ChangeLog)
8 | - [Docker](#Docker)
9 | - [Requirements](#Requirements)
10 | - [Install](#install)
11 | - [Usage](#usage)
12 | - [Related](#Related)
13 | - [Contributing](#contributing)
14 | - [License](#license)
15 |
16 | ## ChangeLog
17 |
18 | - 20200730
19 |
20 | - 独立各类后端配置到 .env 文件中,现在修改后端只需要修改 .env 即可。
21 |
22 |
23 | ## Docker
24 |
25 | ```shell
26 | docker run -d -p 58080:80 --restart always --name subweb careywong/subweb:latest
27 | ```
28 |
29 | 若需要对代码进行修改,你需要在本地构建镜像并运行。
30 | 注:每次修改代码,你都需要重新执行 docker build 来执行打包操作。
31 |
32 | ```shell
33 | docker -v
34 | Docker version 23.0.4, build f480fb1
35 |
36 | docker build -t subweb-local:latest .
37 | docker run -d -p 58080:80 --restart always --name subweb subweb-local:latest
38 | ```
39 |
40 | ## Requirements
41 |
42 | 你需要安装 [Node](https://nodejs.org/zh-cn/) 与 [Yarn](https://legacy.yarnpkg.com/en/docs/install) 来安装依赖与打包发布。你可以通过以下命令查看是否安装成功。
43 | 注:以下步骤为 Ubuntu 下相应命令,其他系统请自行修改。为了方便后来人解决问题,有问题请发 issue。
44 |
45 | ```shell
46 | node -v
47 | v20.xx.x
48 |
49 | yarn -v
50 | 1.22.22
51 | ```
52 |
53 | ## Install
54 |
55 | ```shell
56 | yarn install
57 | ```
58 |
59 | ## Usage
60 |
61 | ```shell
62 | yarn serve
63 | ```
64 |
65 | 浏览器访问
66 |
67 | ## Deploy
68 |
69 | 发布到线上环境,你需要安装依赖,执行以下打包命令,生成的 dist 目录即为发布目录。如需修改默认后端,请修改 src/views/Subconverter.vue 中 **defaultBackend** 配置项。
70 |
71 | ```shell
72 | yarn build
73 | ```
74 |
75 | 你需要安装 nginx (或其他 web 服务器)并正确配置。以下为示例配置,你需要修改 example.com 为自己域名并配置正确的项目根路径(https 自行配置)。
76 |
77 | ```shell
78 | server {
79 | listen 80;
80 | server_name example.com;
81 |
82 | root /var/www/http/sub-web/dist;
83 | index index.html index.htm;
84 |
85 | error_page 404 /index.html;
86 |
87 | gzip on; #开启gzip压缩
88 | gzip_min_length 1k; #设置对数据启用压缩的最少字节数
89 | gzip_buffers 4 16k;
90 | gzip_http_version 1.0;
91 | gzip_comp_level 6; #设置数据的压缩等级,等级为1-9,压缩比从小到大
92 | gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml; #设置需要压缩的数据格式
93 | gzip_vary on;
94 |
95 | location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
96 | access_log off;
97 | add_header Cache-Control "public,max-age=30*24*3600";
98 | }
99 | }
100 | ```
101 |
102 | ## Related
103 |
104 | - [tindy2013/subconverter](https://github.com/tindy2013/subconverter)
105 | - [CareyWang/MyUrls](https://github.com/CareyWang/MyUrls)
106 |
107 | ## Contributing
108 |
109 | PRs accepted.
110 |
111 | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
112 |
113 | ## License
114 |
115 | MIT © 2020 CareyWang
116 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ],
5 | plugins: [
6 | [
7 | "component",
8 | {
9 | "libraryName": "element-ui",
10 | "styleLibraryName": "theme-chalk"
11 | }
12 | ]
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sub-web",
3 | "version": "0.1.0",
4 | "private": true,
5 | "engines": {
6 | "node": ">=20.0.0"
7 | },
8 | "scripts": {
9 | "serve": "vue-cli-service serve",
10 | "build": "vue-cli-service build",
11 | "lint": "vue-cli-service lint"
12 | },
13 | "dependencies": {
14 | "atob": "^2.1.2",
15 | "axios": "^0.21.1",
16 | "btoa": "^1.2.1",
17 | "core-js": "^3.12.1",
18 | "element-ui": "^2.15.1",
19 | "register-service-worker": "^1.7.1",
20 | "vue": "^2.6.10",
21 | "vue-clipboard2": "^0.3.1",
22 | "vue-router": "^3.5.1"
23 | },
24 | "devDependencies": {
25 | "@babel/core": "^7.26.0",
26 | "@babel/eslint-parser": "^7.25.9",
27 | "@vue/cli-plugin-babel": "5",
28 | "@vue/cli-plugin-eslint": "5",
29 | "@vue/cli-plugin-pwa": "5",
30 | "@vue/cli-plugin-router": "5",
31 | "@vue/cli-service": "5",
32 | "babel-plugin-component": "^1.1.1",
33 | "babel-plugin-import": "^1.13.3",
34 | "eslint": "8.56.0",
35 | "eslint-plugin-vue": "9.17.0",
36 | "sass": "^1.43.4",
37 | "sass-loader": "^8.0.0",
38 | "svg-sprite-loader": "6.0.11",
39 | "vue-particles": "^1.0.9",
40 | "vue-template-compiler": "^2.6.10"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | # 单页应用的 Netlify 设置
2 | /* /index.html 200
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-maskable-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/android-chrome-maskable-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-maskable-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/android-chrome-maskable-512x512.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | sub-web
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "sub-web",
3 | "name": "sub-web",
4 | "icon": [
5 | {
6 | "src": "./img/icons/icon-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "./img/icons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "start_url": "index.html",
17 | "display": "standalone",
18 | "background_color": "#002140",
19 | "theme_color": "#002140"
20 | }
21 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/services/.env:
--------------------------------------------------------------------------------
1 | SUBWEB_PORT=58080
2 |
3 | MYURLS_PORT=8002
4 | MYURLS_DOMAIN=example.com
5 | MYURLS_TTL=180
6 |
--------------------------------------------------------------------------------
/services/.gitignore:
--------------------------------------------------------------------------------
1 | data/
2 |
--------------------------------------------------------------------------------
/services/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/services/data/.gitkeep
--------------------------------------------------------------------------------
/services/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 | services:
3 | subweb:
4 | build: ../.
5 | container_name: subweb
6 | restart: always
7 | ports:
8 | - "${SUBWEB_PORT}:80"
9 |
10 | myurls:
11 | image: "careywong/myurls:latest"
12 | container_name: myurls
13 | restart: always
14 | ports:
15 | - "${MYURLS_PORT}:8002"
16 | volumes:
17 | - ./data/myurls/logs:/app/logs
18 | depends_on:
19 | - myurls-redis
20 | entrypoint: ["/app/myurls", "-domain", "${MYURLS_DOMAIN}", "-conn", myurls-redis:6379, "-ttl", "${MYURLS_TTL}"]
21 |
22 | myurls-redis:
23 | image: "redis:5"
24 | container_name: myurls-redis
25 | restart: always
26 | volumes:
27 | - ./data/redis:/data
28 | expose:
29 | - "6379"
30 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/assets/css/element-ui.scss:
--------------------------------------------------------------------------------
1 | // cover some element-ui styles
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 | .cell {
19 | .el-tag {
20 | margin-right: 0px;
21 | }
22 | }
23 |
24 | .small-padding {
25 | .cell {
26 | padding-left: 5px;
27 | padding-right: 5px;
28 | }
29 | }
30 |
31 | .fixed-width {
32 | .el-button--mini {
33 | padding: 7px 10px;
34 | width: 60px;
35 | }
36 | }
37 |
38 | .status-col {
39 | .cell {
40 | padding: 0 10px;
41 | text-align: center;
42 |
43 | .el-tag {
44 | margin-right: 0px;
45 | }
46 | }
47 | }
48 |
49 | // to fixed https://github.com/ElemeFE/element/issues/2461
50 | .el-dialog {
51 | transform: none;
52 | left: 0;
53 | position: relative;
54 | margin: 0 auto;
55 | }
56 |
57 | // refine element ui upload
58 | .upload-container {
59 | .el-upload {
60 | width: 100%;
61 |
62 | .el-upload-dragger {
63 | width: 100%;
64 | height: 200px;
65 | }
66 | }
67 | }
68 |
69 | // dropdown
70 | .el-dropdown-menu {
71 | a {
72 | display: block
73 | }
74 | }
75 |
76 | // fix date-picker ui bug in filter-item
77 | .el-range-editor.el-input__inner {
78 | display: inline-flex !important;
79 | }
--------------------------------------------------------------------------------
/src/assets/css/element-variables.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * I think element-ui's default theme color is too light for long-term use.
3 | * So I modified the default color and you can modify it to your liking.
4 | **/
5 |
6 | /* theme color */
7 | $--color-primary: #304156;
8 | $--color-success: #65C934;
9 | $--color-warning: #E6A23C;
10 | $--color-danger: #F56C6C;
11 | // $--color-info: #1E1E1E;
12 |
13 | $--button-font-weight: 400;
14 |
15 | // $--color-text-regular: #1f2d3d;
16 |
17 | $--border-color-light: #dfe4ed;
18 | $--border-color-lighter: #e6ebf5;
19 |
20 | $--table-border:1px solid#dfe6ec;
21 |
22 | /* icon font path, required */
23 | $--font-path: '~element-ui/lib/theme-chalk/fonts';
24 |
25 | @import "~element-ui/packages/theme-chalk/src/index";
26 |
27 | // the :export directive is the magic sauce for webpack
28 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
29 | :export {
30 | theme: $--color-primary;
31 | }
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CareyWang/sub-web/a8788c1a02e100ada38efc48ab72f390cd41d54c/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/SvgIcon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
34 |
35 |
44 |
--------------------------------------------------------------------------------
/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import SvgIcon from '@/components/SvgIcon'// svg component
3 |
4 | // register globally
5 | Vue.component('svg-icon', SvgIcon)
6 |
7 | const req = require.context('./svg', false, /\.svg$/)
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | requireAll(req)
10 |
--------------------------------------------------------------------------------
/src/icons/svg/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | require(`@/plugins/element-ui`)
5 | require(`@/plugins/clipboard`)
6 | require(`@/plugins/base64`)
7 | require(`@/plugins/particles`)
8 | require(`@/plugins/axios`)
9 | require(`@/plugins/device`)
10 |
11 | import '@/icons' // icon
12 | import './registerServiceWorker'
13 |
14 | Vue.config.productionTip = false
15 |
16 | new Vue({
17 | router,
18 | render: h => h(App)
19 | }).$mount('#app')
20 |
--------------------------------------------------------------------------------
/src/plugins/axios.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import axios from "axios"
3 |
4 | axios.defaults.timeout = 5000 //请求超时的时间设定
5 |
6 | Vue.prototype.$axios = axios
--------------------------------------------------------------------------------
/src/plugins/base64.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import btoa from 'btoa'
3 | import atob from 'atob'
4 |
5 | Vue.prototype.$btoa = (string) => btoa(string)
6 | Vue.prototype.$atob = (string) => atob(string)
7 |
--------------------------------------------------------------------------------
/src/plugins/clipboard.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import clipboard from 'vue-clipboard2'
3 |
4 | Vue.use(clipboard)
5 |
--------------------------------------------------------------------------------
/src/plugins/device.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | Vue.prototype.$getOS = () => {
4 | let ua = navigator.userAgent,
5 | isWindowsPhone = /(?:Windows Phone)/.test(ua),
6 | isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
7 | isAndroid = /(?:Android)/.test(ua),
8 | isFireFox = /(?:Firefox)/.test(ua),
9 | // isChrome = /(?:Chrome|CriOS)/.test(ua),
10 | isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
11 | isIPhone = /(?:iPhone)/.test(ua) && !isTablet,
12 | isPc = !isIPhone && !isAndroid && !isSymbian && !isWindowsPhone;
13 |
14 | return {
15 | isTablet: isTablet,
16 | isIPhone: isIPhone,
17 | isAndroid: isAndroid,
18 | isPc: isPc
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/src/plugins/element-ui.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Element from 'element-ui'
3 | import locale from 'element-ui/lib/locale/lang/zh-CN'
4 | // import '@/assets/css/element-ui.scss'
5 | // import '@/assets/css/element-element-variables.scss'
6 |
7 | Vue.use(Element, {
8 | locale,
9 | size: 'small'
10 | })
11 |
12 | Vue.use(Element.Loading.directive);
13 |
14 | Vue.prototype.$loading = Element.Loading.service;
15 | Vue.prototype.$msgbox = Element.MessageBox;
16 | Vue.prototype.$alert = Element.MessageBox.alert;
17 | Vue.prototype.$confirm = Element.MessageBox.confirm;
18 | Vue.prototype.$prompt = Element.MessageBox.prompt;
19 | Vue.prototype.$notify = Element.Notification;
20 | Vue.prototype.$message = Element.Message;
21 |
--------------------------------------------------------------------------------
/src/plugins/particles.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueParticles from 'vue-particles'
3 |
4 | Vue.use(VueParticles)
5 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from 'register-service-worker'
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}sub-web.js`, {
7 | ready () {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB'
11 | )
12 | },
13 | registered () {
14 | console.log('Service worker has been registered.')
15 | },
16 | cached () {
17 | console.log('Content has been cached for offline use.')
18 | },
19 | updatefound () {
20 | console.log('New content is downloading.')
21 | },
22 | updated () {
23 | console.log('New content is available; please refresh.')
24 | },
25 | offline () {
26 | console.log('No internet connection found. App is running in offline mode.')
27 | },
28 | error (error) {
29 | console.error('Error during service worker registration:', error)
30 | }
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter from "vue-router";
3 |
4 | Vue.use(VueRouter);
5 |
6 | const routes = [
7 | {
8 | path: "/",
9 | name: "SubConverter",
10 | component: () => import("../views/Subconverter.vue")
11 | }
12 | ];
13 |
14 | const router = new VueRouter({
15 | mode: "history",
16 | base: process.env.BASE_URL,
17 | routes
18 | });
19 |
20 | export default router;
21 |
--------------------------------------------------------------------------------
/src/views/Subconverter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Subscription Converter
8 |
9 |
10 |
{{ backendVersion }}
11 |
12 |
13 |
14 |
15 | 基础模式
16 | 进阶模式
17 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 | 前往项目仓库
33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 | 配置示例
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | :
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | 更多选项
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | 定制功能
103 |
104 |
105 | 参考文档
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | 复制
124 |
125 |
126 |
127 |
128 | 复制
130 |
131 |
132 |
133 |
134 | 生成订阅链接
136 | 生成短链接
138 |
139 |
140 |
141 |
142 | 上传配置
144 | 一键导入 Clash
146 |
147 |
148 | 从 URL 解析
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
159 |
160 | Remote config upload
161 |
162 | 参考配置
163 |
164 |
165 |
166 |
167 |
168 |
170 |
171 |
172 |
176 |
177 |
178 |
180 |
181 | 解析 Subconverter 链接
182 |
183 |
184 |
185 |
186 |
187 |
188 |
192 |
193 |
194 |
195 |
196 |
197 |
758 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | function resolve(dir) {
4 | return path.join(__dirname, dir)
5 | }
6 |
7 | module.exports = {
8 | css: {
9 | loaderOptions: {
10 | less: {
11 | javascriptEnabled: true
12 | }
13 | }
14 | },
15 |
16 | chainWebpack: config => {
17 | // set svg-sprite-loader
18 | config.module
19 | .rule('svg')
20 | .exclude.add(resolve('src/icons'))
21 | .end()
22 | config.module
23 | .rule('icons')
24 | .test(/\.svg$/)
25 | .include.add(resolve('src/icons'))
26 | .end()
27 | .use('svg-sprite-loader')
28 | .loader('svg-sprite-loader')
29 | .options({
30 | symbolId: 'icon-[name]'
31 | })
32 | .end()
33 | },
34 |
35 | pwa: {
36 | workboxOptions: {
37 | // https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin
38 | skipWaiting: true,
39 | clientsClaim: true,
40 | importScripts: [
41 | 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js'
42 | ],
43 | navigateFallback: '/',
44 | navigateFallbackDenylist: [/\/api\//]
45 | }
46 | }
47 | };
48 |
--------------------------------------------------------------------------------