├── babel.config.js
├── public
├── favicon.ico
└── index.html
├── src
├── assets
│ ├── vue-imgs-preview.gif
│ ├── imgPre-minus-on.svg
│ ├── imgPre-minus.svg
│ ├── imgPre-plus.svg
│ ├── imgPre-plus-on.svg
│ ├── imgPre-right.svg
│ ├── imgPre-close1.svg
│ ├── imgPre-close.svg
│ └── icon.svg
├── main.js
├── lib
│ ├── index.js
│ ├── vue-imgs.css
│ ├── vue-imgs.less
│ └── vue-imgs-preview.vue
├── App.vue
└── components
│ └── HelloWorld.vue
├── .npmignore
├── .gitignore
├── vue.config.js
├── package.json
└── README.md
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaleWeb/vue-imgs-preview/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/vue-imgs-preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaleWeb/vue-imgs-preview/HEAD/src/assets/vue-imgs-preview.gif
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # 忽略目录
2 | examples/
3 | packages/
4 | public/
5 |
6 |
7 | # 忽略指定文件
8 | vue.config.js
9 | babel.config.js
10 | *.map
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import VueImgsPreview from 'vue-imgs-preview'
4 | // import VueImgsPreview from './lib/index.js'
5 |
6 | Vue.use(VueImgsPreview);
7 | Vue.config.productionTip = false
8 |
9 | new Vue({
10 | render: h => h(App),
11 | }).$mount('#app')
12 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | configureWebpack:()=>{
3 | return {
4 | entry:'./src/main.js',
5 | output:{
6 | library:'test',
7 | libraryTarget:'umd',
8 | umdNamedDefine:true
9 | }
10 | }
11 | },
12 | css:{ extract: false},
13 | lintOnSave:false
14 | }
--------------------------------------------------------------------------------
/src/lib/index.js:
--------------------------------------------------------------------------------
1 | import vueImgsPreview from './vue-imgs-preview.vue'
2 | const components = [vueImgsPreview]
3 | const install = function (Vue){
4 | if(install.installed) return;
5 | components.map(component=>Vue.component(component.name,component))
6 | }
7 | if(typeof window!=="undefined"&&window.Vue){
8 | install(window.Vue);
9 | }
10 | export default {
11 | install,
12 | vueImgsPreview
13 | }
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | vue-img-preview
9 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/assets/imgPre-minus-on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/imgPre-minus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/imgPre-plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/imgPre-plus-on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |

5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
25 |
26 |
36 |
--------------------------------------------------------------------------------
/src/assets/imgPre-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/imgPre-close1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-imgs-preview",
3 | "version": "0.2.0",
4 | "description": "图片查看工具,支持放大、下载、旋转、拖拽等",
5 | "author": "MaleWeb",
6 | "main": "dist/vueImgsPreview.common.js",
7 | "unpkg": "dist/vueImgsPreview.umd.min.js",
8 | "license": "MIT",
9 | "scripts": {
10 | "serve": "vue-cli-service serve",
11 | "build": "vue-cli-service build",
12 | "lint": "vue-cli-service lint",
13 | "lib": "vue-cli-service build --target lib --name vueImgsPreview ./src/lib/index.js"
14 | },
15 | "publishConfig": {
16 | "registry": "https://registry.npmjs.org/"
17 | },
18 | "files": [
19 | "dist"
20 | ],
21 | "dependencies": {
22 | "vue": "^2.6.6",
23 | "vue-images-preview": "^1.0.0",
24 | "vue-imgs-preview": "^0.1.6"
25 | },
26 | "devDependencies": {
27 | "@vue/cli-plugin-babel": "^3.4.0",
28 | "@vue/cli-plugin-eslint": "^3.4.0",
29 | "@vue/cli-service": "^3.4.0",
30 | "babel-eslint": "^10.0.1",
31 | "eslint": "^5.8.0",
32 | "eslint-plugin-vue": "^5.0.0",
33 | "vue-template-compiler": "^2.5.21"
34 | },
35 | "eslintConfig": {
36 | "root": true,
37 | "env": {
38 | "node": true
39 | },
40 | "extends": [
41 | "plugin:vue/essential",
42 | "eslint:recommended"
43 | ],
44 | "rules": {}
45 | },
46 | "postcss": {
47 | "plugins": {
48 | "autoprefixer": {}
49 | }
50 | },
51 | "browserslist": [
52 | "> 1%",
53 | "last 2 versions",
54 | "not ie <= 8"
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 前端之路,不虚此行
8 |
9 | # VueImgsPreview
10 | [](https://www.npmjs.com/package/vue-imgs-preview)
11 | 
12 |
13 | 基于vue-cli3的图片预览插件
14 |
15 | `花了一天的时间,抽离了一个业务中的组件。写的不好,请多指教`
16 |
17 | ## 预览
18 |
19 | 
20 |
21 | ## 功能
22 |
23 | + 图片的拖拽事件
24 |
25 | + 图片下载功能
26 |
27 | + 图片左右切换功能
28 |
29 | + 检索Dom内所有图片,添加点击事件
30 |
31 | + 图片的放大缩小功能,支持鼠标滚轮事件
32 |
33 |
34 | ## Use
35 |
36 | ### install
37 | ```
38 | npm install vue-imgs-preview --save
39 |
40 | Vue.use(VueImgsPreview)
41 | ```
42 |
43 | ### main.js
44 |
45 | ```
46 | import VueImgsPreview from 'vue-imgs-preview'
47 | ```
48 | ### App.vue
49 |
50 | ```
51 |
52 | ```
53 |
54 | ## API
55 |
56 | |参数 | 说明 | 类型 | 默认值 |
57 | |---|---|---|---|
58 | |imgPre | 组件的显示状态| Boolean | false|
59 | |articleId | 文章Dom的ID | String | null |
60 |
61 | ## About
62 |
63 | 有任何问题都可以先Star,后留言;
64 | 加入群一起探索前端世界
65 |
66 | 
67 |
--------------------------------------------------------------------------------
/src/assets/imgPre-close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/lib/vue-imgs.css:
--------------------------------------------------------------------------------
1 | .vue-imgs-preview {
2 | position: fixed;
3 | width: 100%;
4 | height: 100%;
5 | top: 0px;
6 | left: 0px;
7 | z-index: 9999;
8 | background-color: rgba(255, 255, 255, 0.9);
9 | overflow: hidden;
10 | display: -webkit-box;
11 | display: -ms-flexbox;
12 | display: flex;
13 | -webkit-box-orient: vertical;
14 | -webkit-box-direction: normal;
15 | -ms-flex-direction: column;
16 | flex-direction: column;
17 | -webkit-box-pack: center;
18 | -ms-flex-pack: center;
19 | justify-content: center;
20 | -webkit-box-align: center;
21 | -ms-flex-align: center;
22 | align-items: center;
23 | }
24 | .vue-imgs-preview .img-box {
25 | cursor: move;
26 | position: absolute;
27 | z-index: 10005;
28 | }
29 | .vue-imgs-preview .img-box img {
30 | width: 100%;
31 | height: 100%;
32 | }
33 | .vue-imgs-preview ul.tools {
34 | text-align: center;
35 | position: fixed;
36 | bottom: 20px;
37 | padding: 0 5px;
38 | left: 50%;
39 | margin-left: -163px;
40 | z-index: 10006;
41 | height: 56px;
42 | border-radius: 2px;
43 | background-color: rgba(255, 255, 255, 0.9);
44 | box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
45 | border: solid 1px #f2f2f2;
46 | min-width: 326px;
47 | }
48 | .vue-imgs-preview ul.tools li {
49 | cursor: default;
50 | display: inline-block;
51 | margin: 10px;
52 | cursor: pointer;
53 | position: relative;
54 | height: 24px;
55 | vertical-align: baseline;
56 | moz-user-select: -moz-none;
57 | -moz-user-select: none;
58 | -o-user-select: none;
59 | -khtml-user-select: none;
60 | -webkit-user-select: none;
61 | -ms-user-select: none;
62 | user-select: none;
63 | }
64 | .vue-imgs-preview ul.tools li:hover .icon-plus {
65 | display: none;
66 | }
67 | .vue-imgs-preview ul.tools li:hover .icon-plus-on {
68 | display: inline-block;
69 | }
70 | .vue-imgs-preview ul.tools li:hover .icon-minus {
71 | display: none;
72 | }
73 | .vue-imgs-preview ul.tools li:hover .icon-minus-on {
74 | display: inline-block;
75 | }
76 | .vue-imgs-preview ul.tools li i {
77 | display: inline-block;
78 | background-size: 100% 100%;
79 | width: 26px;
80 | height: 26px;
81 | }
82 | .vue-imgs-preview ul.tools li .image-index {
83 | top: -4px;
84 | position: relative;
85 | font-size: 16px;
86 | color: #676767;
87 | }
88 | .vue-imgs-preview ul.tools li .separate-line {
89 | position: relative;
90 | top: 6px;
91 | display: inline-block;
92 | margin-left: 22px;
93 | cursor: default;
94 | width: 1px;
95 | height: 30px;
96 | background: #e7e7e7;
97 | }
98 | .vue-imgs-preview ul.tools li .icon-plus {
99 | background: url(../assets/imgPre-plus.svg) no-repeat;
100 | background-size: 100% 100%;
101 | width: 26px;
102 | height: 26px;
103 | }
104 | .vue-imgs-preview ul.tools li .icon-plus-on {
105 | display: none;
106 | width: 26px;
107 | height: 26px;
108 | background: url(../assets/imgPre-plus-on.svg) no-repeat;
109 | background-size: 100% 100%;
110 | }
111 | .vue-imgs-preview ul.tools li .icon-minus {
112 | background: url(../assets/imgPre-minus.svg) no-repeat;
113 | background-size: 100% 100%;
114 | width: 26px;
115 | height: 26px;
116 | }
117 | .vue-imgs-preview ul.tools li .icon-minus-on {
118 | display: none;
119 | width: 26px;
120 | height: 26px;
121 | background: url(../assets/imgPre-minus-on.svg) no-repeat;
122 | background-size: 100% 100%;
123 | }
124 | .vue-imgs-preview ul.tools li .icon-turn-left {
125 | background: url(../assets/icon.svg) no-repeat;
126 | background-position: 65.22988505747126% 54.98489425981873%;
127 | width: 29px;
128 | height: 26px;
129 | }
130 | .vue-imgs-preview ul.tools li .icon-turn-left:hover {
131 | background-position: 0 66.76737160120845%;
132 | }
133 | .vue-imgs-preview ul.tools li .icon-preview-dl {
134 | background: url(../assets/icon.svg) no-repeat;
135 | background-position: 74.35897435897436% 39.879154078549846%;
136 | width: 26px;
137 | height: 26px;
138 | }
139 | .vue-imgs-preview ul.tools li .icon-preview-dl:hover {
140 | background-position: 74.35897435897436% 8.459214501510575%;
141 | }
142 | .vue-imgs-preview ul.tools li .icon-preview-fit-size {
143 | background: url(../assets/icon.svg) no-repeat;
144 | background-position: 74.35897435897436% 16.31419939577039%;
145 | width: 26px;
146 | height: 26px;
147 | }
148 | .vue-imgs-preview ul.tools li .icon-preview-fit-size:hover {
149 | background-position: 74.35897435897436% 47.73413897280967%;
150 | }
151 | .vue-imgs-preview .info {
152 | color: white;
153 | position: fixed;
154 | top: 0;
155 | line-height: 40px;
156 | width: 100%;
157 | background-color: rgba(255, 255, 255, 0.9);
158 | z-index: 10006;
159 | }
160 | .vue-imgs-preview .info .image-buttons {
161 | position: absolute;
162 | top: 30px;
163 | right: 30px;
164 | border-radius: 50%;
165 | box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1);
166 | border: solid 1px #efefef;
167 | width: 44px;
168 | height: 44px;
169 | background: #fff;
170 | cursor: pointer;
171 | }
172 | .vue-imgs-preview .info .image-buttons .close {
173 | width: 44px;
174 | margin-top: 12px;
175 | }
176 | .vue-imgs-preview .info .image-buttons .close .icon {
177 | text-align: center;
178 | background: url(../assets/imgPre-close1.svg) no-repeat;
179 | background-size: 100% 100%;
180 | width: 20px;
181 | height: 20px;
182 | display: block;
183 | margin: 0 auto;
184 | }
185 | .vue-imgs-preview .bi-zoom-prev,
186 | .vue-imgs-preview .bi-zoom-next {
187 | position: absolute;
188 | width: 48px;
189 | height: 48px;
190 | display: block;
191 | top: 50%;
192 | margin-top: -24px;
193 | background-color: rgba(255, 255, 255, 0.9);
194 | box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
195 | border: solid 1px #f2f2f2;
196 | z-index: 11000;
197 | text-align: center;
198 | line-height: 48px;
199 | cursor: pointer;
200 | }
201 | .vue-imgs-preview .bi-zoom-prev .icon-turn-next,
202 | .vue-imgs-preview .bi-zoom-next .icon-turn-next {
203 | background-image: url("../assets/imgPre-right.svg");
204 | background-size: 100% 100%;
205 | }
206 | .vue-imgs-preview .bi-zoom-prev .icon-turn-prev,
207 | .vue-imgs-preview .bi-zoom-next .icon-turn-prev {
208 | margin-top: -5px;
209 | background-image: url("../assets/imgPre-right.svg");
210 | transform: rotate(180deg);
211 | -webkit-transform: rotate(180deg);
212 | }
213 | .vue-imgs-preview .bi-zoom-prev i,
214 | .vue-imgs-preview .bi-zoom-next i {
215 | width: 30px;
216 | height: 48px;
217 | line-height: 48px;
218 | margin: 0 auto;
219 | font-size: 26px;
220 | background-repeat: no-repeat;
221 | display: inline-block;
222 | font-style: normal;
223 | vertical-align: baseline;
224 | text-align: center;
225 | text-transform: none;
226 | text-rendering: auto;
227 | }
228 | .vue-imgs-preview .bi-zoom-next {
229 | right: 0;
230 | }
231 | .vue-imgs-preview .bi-zoom-prev {
232 | left: 0;
233 | }
234 |
--------------------------------------------------------------------------------
/src/lib/vue-imgs.less:
--------------------------------------------------------------------------------
1 | .vue-imgs-preview {
2 | position: fixed;
3 | width: 100%;
4 | height: 100%;
5 | top: 0px;
6 | left: 0px;
7 | z-index: 9999;
8 | background-color: rgba(255, 255, 255, 0.9);
9 | overflow: hidden;
10 | display: -webkit-box;
11 | display: -ms-flexbox;
12 | display: flex;
13 | -webkit-box-orient: vertical;
14 | -webkit-box-direction: normal;
15 | -ms-flex-direction: column;
16 | flex-direction: column;
17 | -webkit-box-pack: center;
18 | -ms-flex-pack: center;
19 | justify-content: center;
20 | -webkit-box-align: center;
21 | -ms-flex-align: center;
22 | align-items: center;
23 | .img-box {
24 | cursor: move;
25 | position: absolute;
26 | z-index: 10005;
27 | img {
28 | width: 100%;
29 | height: 100%;
30 | }
31 | }
32 | ul.tools {
33 | text-align: center;
34 | position: fixed;
35 | bottom: 20px;
36 | padding: 0 5px;
37 | left: 50%;
38 | margin-left: -163px;
39 | z-index: 10006;
40 | height: 56px;
41 | border-radius: 2px;
42 | background-color: rgba(255, 255, 255, 0.9);
43 | box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
44 | border: solid 1px #f2f2f2;
45 | min-width: 326px;
46 | li {
47 | cursor: default;
48 | display: inline-block;
49 | margin: 10px;
50 | cursor: pointer;
51 | position: relative;
52 | height: 24px;
53 | vertical-align: baseline;
54 | moz-user-select: -moz-none;
55 | -moz-user-select: none;
56 | -o-user-select: none;
57 | -khtml-user-select: none;
58 | -webkit-user-select: none;
59 | -ms-user-select: none;
60 | user-select: none;
61 | &:hover {
62 | .icon-plus {
63 | display: none;
64 | }
65 | .icon-plus-on {
66 | display: inline-block;
67 | }
68 | .icon-minus {
69 | display: none;
70 | }
71 | .icon-minus-on {
72 | display: inline-block;
73 | }
74 | }
75 | i {
76 | display: inline-block;
77 | background-size: 100% 100%;
78 | width: 26px;
79 | height: 26px;
80 | }
81 | .image-index {
82 | top: -4px;
83 | position: relative;
84 | font-size: 16px;
85 | color: #676767;
86 | }
87 | .separate-line {
88 | position: relative;
89 | top: 6px;
90 | display: inline-block;
91 | margin-left: 22px;
92 | cursor: default;
93 | width: 1px;
94 | height: 30px;
95 | background: #e7e7e7;
96 | }
97 | .icon-plus {
98 | background: url(../assets/imgPre-plus.svg) no-repeat;
99 | background-size: 100% 100%;
100 | width: 26px;
101 | height: 26px;
102 | }
103 | .icon-plus-on {
104 | display: none;
105 | width: 26px;
106 | height: 26px;
107 | background: url(../assets/imgPre-plus-on.svg) no-repeat;
108 | background-size: 100% 100%;
109 | }
110 | .icon-minus {
111 | background: url(../assets/imgPre-minus.svg) no-repeat;
112 | background-size: 100% 100%;
113 | width: 26px;
114 | height: 26px;
115 | }
116 | .icon-minus-on {
117 | display: none;
118 | width: 26px;
119 | height: 26px;
120 | background: url(../assets/imgPre-minus-on.svg) no-repeat;
121 | background-size: 100% 100%;
122 | }
123 | .icon-turn-left {
124 | background: url(../assets/icon.svg) no-repeat;
125 | background-position: 65.22988505747126% 54.98489425981873%;
126 | width: 29px;
127 | height: 26px;
128 | &:hover {
129 | background-position: 0 66.76737160120845%;
130 | }
131 | }
132 | .icon-preview-dl {
133 | background: url(../assets/icon.svg) no-repeat;
134 | background-position: 74.35897435897436% 39.879154078549846%;
135 | width: 26px;
136 | height: 26px;
137 | &:hover {
138 | background-position: 74.35897435897436% 8.459214501510575%;
139 | }
140 | }
141 | .icon-preview-fit-size {
142 | background: url(../assets/icon.svg) no-repeat;
143 | background-position: 74.35897435897436% 16.31419939577039%;
144 | width: 26px;
145 | height: 26px;
146 | &:hover {
147 | background-position: 74.35897435897436% 47.73413897280967%;
148 | }
149 | }
150 | }
151 | }
152 | .info {
153 | color: white;
154 | position: fixed;
155 | top: 0;
156 | line-height: 40px;
157 | width: 100%;
158 | background-color: rgba(255, 255, 255, 0.9);
159 | z-index: 10006;
160 | .image-buttons {
161 | position: absolute;
162 | top: 30px;
163 | right: 30px;
164 | border-radius: 50%;
165 | box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.1);
166 | border: solid 1px #efefef;
167 | width: 44px;
168 | height: 44px;
169 | background: #fff;
170 | cursor: pointer;
171 | .close {
172 | width: 44px;
173 | margin-top: 12px;
174 | .icon {
175 | text-align: center;
176 | background: url(../assets/imgPre-close1.svg) no-repeat;
177 | background-size: 100% 100%;
178 | width: 20px;
179 | height: 20px;
180 | display: block;
181 | margin: 0 auto;
182 | // margin-left: 11px;
183 | }
184 | }
185 | }
186 | }
187 | .bi-zoom-prev,
188 | .bi-zoom-next {
189 | position: absolute;
190 | width: 48px;
191 | height: 48px;
192 | display: block;
193 | top: 50%;
194 | margin-top: -24px;
195 | background-color: rgba(255, 255, 255, 0.9);
196 | box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.15);
197 | border: solid 1px #f2f2f2;
198 | z-index: 11000;
199 | text-align: center;
200 | line-height: 48px;
201 | cursor: pointer;
202 | .icon-turn-next {
203 | background-image: url("../assets/imgPre-right.svg");
204 | background-size: 100% 100%;
205 | }
206 | .icon-turn-prev {
207 | margin-top: -5px;
208 | background-image: url("../assets/imgPre-right.svg");
209 | transform: rotate(180deg);
210 | -webkit-transform: rotate(180deg);
211 | }
212 | i {
213 | width: 30px;
214 | height: 48px;
215 | line-height: 48px;
216 | margin: 0 auto;
217 | font-size: 26px;
218 | background-repeat: no-repeat;
219 | display: inline-block;
220 | font-style: normal;
221 | vertical-align: baseline;
222 | text-align: center;
223 | text-transform: none;
224 | text-rendering: auto;
225 | }
226 | }
227 | .bi-zoom-next {
228 | right: 0;
229 | }
230 | .bi-zoom-prev {
231 | left: 0;
232 | }
233 | }
--------------------------------------------------------------------------------
/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |
9 |
Installed CLI Plugins
10 |
14 |
Essential Links
15 |
22 |
Ecosystem
23 |
30 |
31 |
32 |
33 |
34 |
47 |
48 |
49 |
65 |
--------------------------------------------------------------------------------
/src/lib/vue-imgs-preview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
![]()
11 |
12 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
48 |
49 |
50 |
51 |
273 |
--------------------------------------------------------------------------------
/src/assets/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------