nanosplash 3.1.1 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +8 -2
- package/.github/workflows/vitepress.yml +1 -1
- package/docs/.vitepress/config.ts +3 -0
- package/docs/.vitepress/theme/vue/PlayGround.vue +0 -2
- package/docs/api/start/install.md +9 -5
- package/docs/api/start/playground.md +6 -1
- package/package.json +89 -90
- package/src/ts/Nanosplash.ts +154 -186
- package/src/ts/main.ts +3 -1
- package/src/ts/types/Types.ts +0 -13
- package/tests/Nanosplash.spec.ts +5 -15
- package/dist/cjs/ns.cjs +0 -1
- package/dist/es/ns.js +0 -44
- package/dist/iife/ns.iife.js +0 -1
- package/docs/.vitepress/theme/vue/Exe.vue +0 -121
package/.github/workflows/ci.yml
CHANGED
|
@@ -25,7 +25,7 @@ jobs:
|
|
|
25
25
|
uses: actions/setup-node@v3
|
|
26
26
|
with:
|
|
27
27
|
node-version: 20
|
|
28
|
-
|
|
28
|
+
registry-url: 'https://registry.npmjs.org'
|
|
29
29
|
- name: Set up Git and update production branch
|
|
30
30
|
run: |
|
|
31
31
|
git config --global user.name "GitHub Actions"
|
|
@@ -38,7 +38,7 @@ jobs:
|
|
|
38
38
|
uses: actions/configure-pages@v3
|
|
39
39
|
|
|
40
40
|
- name: Install dependencies
|
|
41
|
-
run: pnpm install
|
|
41
|
+
run: pnpm install --no-frozen-lockfile
|
|
42
42
|
|
|
43
43
|
- name: Build (Vite)
|
|
44
44
|
run: pnpm build
|
|
@@ -52,5 +52,11 @@ jobs:
|
|
|
52
52
|
- name: Commit and push changes
|
|
53
53
|
run: |
|
|
54
54
|
git add .
|
|
55
|
+
git add -f coverage/**/* dist/**/*
|
|
55
56
|
git commit --allow-empty -m "Build, test, and coverage report"
|
|
56
57
|
git push
|
|
58
|
+
|
|
59
|
+
- name: Publish to NPM
|
|
60
|
+
run: npm publish
|
|
61
|
+
env:
|
|
62
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
|
@@ -6,6 +6,9 @@ export default defineConfig({
|
|
|
6
6
|
description: 'The tiny loading screen for web artisans',
|
|
7
7
|
base: '/nanosplash/',
|
|
8
8
|
appearance: 'dark',
|
|
9
|
+
head: [
|
|
10
|
+
['script', { src: 'https://unpkg.com/nanosplash/dist/iife/ns.iife.js' }],
|
|
11
|
+
],
|
|
9
12
|
themeConfig: {
|
|
10
13
|
nav: [
|
|
11
14
|
{ text: 'Home', link: '/' },
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import CardGrid from './CardGrid.vue'
|
|
3
3
|
import Card from './Card.vue'
|
|
4
|
-
import Exe from './Exe.vue'
|
|
5
4
|
</script>
|
|
6
5
|
|
|
7
6
|
<template>
|
|
@@ -20,7 +19,6 @@ import Exe from './Exe.vue'
|
|
|
20
19
|
Lorem ipsum dolor sit amet consectetur adipiscing elit ut aliquam
|
|
21
20
|
</Card>
|
|
22
21
|
</CardGrid>
|
|
23
|
-
<Exe />
|
|
24
22
|
</div>
|
|
25
23
|
</template>
|
|
26
24
|
|
|
@@ -18,15 +18,15 @@ Add the following script tag inside of the `<body>` tag:
|
|
|
18
18
|
<script src="https://unpkg.com/nanosplash/dist/iife/ns.iife.js"></script>
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
### Example
|
|
22
|
+
|
|
23
|
+
```html{6}
|
|
22
24
|
<html>
|
|
23
25
|
<head>
|
|
24
|
-
<meta charset="UTF-8" />
|
|
25
26
|
<title>My awesome application 🚀</title>
|
|
26
27
|
</head>
|
|
27
28
|
<body>
|
|
28
29
|
<script src="https://unpkg.com/nanosplash/dist/iife/ns.iife.js"></script>
|
|
29
|
-
...
|
|
30
30
|
</body>
|
|
31
31
|
</html>
|
|
32
32
|
```
|
|
@@ -53,5 +53,9 @@ const ns = useNs()
|
|
|
53
53
|
ns.show('It works!')
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
For ease of use, add it to the window object for global access.
|
|
57
|
+
|
|
58
|
+
```js{2}
|
|
59
|
+
import { useNs } from 'nanosplash'
|
|
60
|
+
window.ns = useNs()
|
|
61
|
+
```
|
|
@@ -8,4 +8,9 @@ Here you can play around with Nanosplash and see how it works.
|
|
|
8
8
|
|
|
9
9
|
<PlayGround />
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Open your browser console (developer tools).
|
|
12
|
+
|
|
13
|
+
- macOS: `⌘` `⌥` `i`
|
|
14
|
+
- Windows: `Ctrl` `⇧` `i`
|
|
15
|
+
|
|
16
|
+
Try to target different elements in the DOM. Nanosplash is available in the window scope as `ns`. Give it a shot!
|
package/package.json
CHANGED
|
@@ -1,91 +1,90 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
}
|
|
2
|
+
"name": "nanosplash",
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Isak K. Hauge",
|
|
6
|
+
"email": "isakhauge@icloud.com",
|
|
7
|
+
"url": "https://no.linkedin.com/in/isakhauge"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/isakhauge/nanosplash.git"
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/es/ns.js",
|
|
14
|
+
"module": "./dist/es/ns.js",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/jsdom": "^21.1.6",
|
|
17
|
+
"@types/node": "^20.11.30",
|
|
18
|
+
"@vitest/coverage-v8": "^1.4.0",
|
|
19
|
+
"@vitest/ui": "^1.4.0",
|
|
20
|
+
"cross-env": "^7.0.3",
|
|
21
|
+
"eslint": "^8.57.0",
|
|
22
|
+
"eslint-config-prettier": "^9.1.0",
|
|
23
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
24
|
+
"jsdom": "^24.0.0",
|
|
25
|
+
"sass": "^1.72.0",
|
|
26
|
+
"stylelint-prettier": "^5.0.0",
|
|
27
|
+
"typescript": "5.4.3",
|
|
28
|
+
"typescript-eslint": "^7.3.1",
|
|
29
|
+
"vite": "^5.2.6",
|
|
30
|
+
"vitepress": "1.0.1",
|
|
31
|
+
"vitest": "^1.4.0"
|
|
32
|
+
},
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": {
|
|
36
|
+
"require": "./src/ts/types/global.d.ts",
|
|
37
|
+
"default": "./src/ts/types/global.d.ts"
|
|
38
|
+
},
|
|
39
|
+
"browser": {
|
|
40
|
+
"require": "./dist/cjs/ns.cjs",
|
|
41
|
+
"default": "./dist/es/ns.js"
|
|
42
|
+
},
|
|
43
|
+
"default": {
|
|
44
|
+
"require": "./dist/cjs/ns.cjs",
|
|
45
|
+
"default": "./dist/es/ns.js"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"description": "The tiny loading screen for web artisans",
|
|
50
|
+
"homepage": "https://isakhauge.github.io/nanosplash",
|
|
51
|
+
"keywords": [
|
|
52
|
+
"loading",
|
|
53
|
+
"loader",
|
|
54
|
+
"screen",
|
|
55
|
+
"splash",
|
|
56
|
+
"nano",
|
|
57
|
+
"nanosplash",
|
|
58
|
+
"small",
|
|
59
|
+
"tiny",
|
|
60
|
+
"es",
|
|
61
|
+
"esm",
|
|
62
|
+
"ts",
|
|
63
|
+
"typescript",
|
|
64
|
+
"iife",
|
|
65
|
+
"cdn",
|
|
66
|
+
"vite"
|
|
67
|
+
],
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"private": false,
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "pnpm build:all && pnpm build:docs",
|
|
72
|
+
"build:es": "tsc && cross-env entry=./src/ts/Nanosplash.ts format=es vite build -m production --c vite.config.ts",
|
|
73
|
+
"build:cjs": "tsc && cross-env entry=./src/ts/Nanosplash.ts format=cjs vite build -m production --c vite.config.ts",
|
|
74
|
+
"build:iife": "tsc && cross-env entry=./src/ts/main.ts format=iife vite build -m production --c vite.config.ts",
|
|
75
|
+
"build:all": "pnpm build:es && pnpm build:cjs && pnpm build:iife",
|
|
76
|
+
"build:docs": "pnpm docs:build",
|
|
77
|
+
"preview": "vite preview",
|
|
78
|
+
"test": "vitest",
|
|
79
|
+
"test:ui": "vitest --ui",
|
|
80
|
+
"lint": "eslint src/ts/**/*.ts --fix",
|
|
81
|
+
"coverage": "vitest --coverage",
|
|
82
|
+
"docs:dev": "pnpm exec vitepress dev docs",
|
|
83
|
+
"docs:build": "pnpm exec vitepress build docs",
|
|
84
|
+
"docs:preview": "pnpm exec vitepress preview docs"
|
|
85
|
+
},
|
|
86
|
+
"source": "./src/main.ts",
|
|
87
|
+
"type": "module",
|
|
88
|
+
"types": "./src/ts/types/global.d.ts",
|
|
89
|
+
"unpkg": "./dist/iife/ns.iife.js"
|
|
90
|
+
}
|
package/src/ts/Nanosplash.ts
CHANGED
|
@@ -1,209 +1,177 @@
|
|
|
1
1
|
// @ts-strict
|
|
2
2
|
import style from '../style/ns.sass?inline'
|
|
3
3
|
import { NanosplashInterface } from './types/NanosplashInterface'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
ElementReference,
|
|
7
|
-
NSElement,
|
|
8
|
-
ScopedSelectors,
|
|
9
|
-
} from './types/Types'
|
|
4
|
+
import { ElementReference, NSElement } from './types/Types'
|
|
5
|
+
import type { DOMWindow } from 'jsdom'
|
|
10
6
|
import { version } from '../../package.json'
|
|
11
7
|
|
|
12
|
-
const styleId: string = 'ns'
|
|
13
|
-
const doc: Document = document
|
|
14
|
-
const bod: HTMLElement = doc.body
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* # Scope
|
|
18
|
-
* Creates scoped selectors.
|
|
19
|
-
* @param node Node to query.
|
|
20
|
-
* @returns An object containing two, slightly different functions that
|
|
21
|
-
* retrieves elements from the DOM.
|
|
22
|
-
*/
|
|
23
|
-
const scope = (node: ParentNode): ScopedSelectors =>
|
|
24
|
-
(all => ({
|
|
25
|
-
all,
|
|
26
|
-
first: (ref: string) => all(ref)[0] ?? null,
|
|
27
|
-
}))((ref: string) => Array.from(node.querySelectorAll(ref)))
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* # Get all
|
|
31
|
-
* @param selector CSS selector used to match nodes in the DOM.
|
|
32
|
-
* @returns An array of Element nodes.
|
|
33
|
-
*/
|
|
34
|
-
const getAll = (selector: DOMSelector): Element[] => scope(doc).all(selector)
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* # Get
|
|
38
|
-
* @param selector CSS selector used to match nodes in the DOM.
|
|
39
|
-
* @returns Firs Element node from the DOM matching the selector.
|
|
40
|
-
*/
|
|
41
|
-
const get = (selector: DOMSelector): Element | null =>
|
|
42
|
-
scope(doc).first(selector)
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* # Get All Nanosplashes
|
|
46
|
-
* @returns An array of all Nanosplash elements in the DOM.
|
|
47
|
-
*/
|
|
48
|
-
const getAllNs = (): NSElement[] => getAll('.ns') as NSElement[]
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* # Parse Ref
|
|
52
|
-
* @param ref Element reference which could be a selector or an Element.
|
|
53
|
-
* @returns The Element node or null.
|
|
54
|
-
*/
|
|
55
|
-
const parseRef = (ref: ElementReference): Element | null =>
|
|
56
|
-
ref instanceof Element ? ref : get(ref)
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* # Create HTMLDivElement
|
|
60
|
-
* @param className Optional string containing class names.
|
|
61
|
-
* @param children Optional list of Nodes or strings.
|
|
62
|
-
* @returns The newly created HTMLDivElement.
|
|
63
|
-
*/
|
|
64
|
-
const div = (
|
|
65
|
-
className?: string,
|
|
66
|
-
...children: (Node | string)[]
|
|
67
|
-
): HTMLDivElement => {
|
|
68
|
-
const node: HTMLDivElement = doc.createElement('div')
|
|
69
|
-
if (className) node.classList.add(className)
|
|
70
|
-
node.append(...children)
|
|
71
|
-
return node
|
|
72
|
-
}
|
|
73
|
-
|
|
74
8
|
/**
|
|
75
|
-
* #
|
|
76
|
-
* @
|
|
77
|
-
* @returns Parsed node.
|
|
78
|
-
*/
|
|
79
|
-
const parse = (html: string): Node => {
|
|
80
|
-
const node: HTMLDivElement = div()
|
|
81
|
-
node.innerHTML = html
|
|
82
|
-
return node.firstChild as Node
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* # Make Nanosplash Element
|
|
87
|
-
* @returns Nanpslash DOM element.
|
|
9
|
+
* # Use Nanosplash
|
|
10
|
+
* @returns Nanosplash API.
|
|
88
11
|
*/
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
12
|
+
export const useNs = (
|
|
13
|
+
win?: (Window | (Window & typeof globalThis)) | DOMWindow
|
|
14
|
+
): NanosplashInterface => {
|
|
15
|
+
const doc = () => (win ?? window).document
|
|
16
|
+
const bod = () => doc().body
|
|
17
|
+
|
|
18
|
+
const all = (node: ParentNode, ref: string) =>
|
|
19
|
+
Array.from(node.querySelectorAll(ref))
|
|
20
|
+
const first = (node: ParentNode, ref: string) => all(node, ref)[0] ?? null
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* # Get All Nanosplashes
|
|
24
|
+
* @returns An array of all Nanosplash elements in the DOM.
|
|
25
|
+
*/
|
|
26
|
+
const getAllNs = (): NSElement[] => all(doc(), '.ns') as NSElement[]
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* # Parse Ref
|
|
30
|
+
* @param ref Element reference which could be a selector or an Element.
|
|
31
|
+
* @returns The Element node or null.
|
|
32
|
+
*/
|
|
33
|
+
const parseRef = (ref: ElementReference): Element | null =>
|
|
34
|
+
ref instanceof Element ? ref : first(doc(), ref)
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* # Create HTMLDivElement
|
|
38
|
+
* @param className Optional string containing class names.
|
|
39
|
+
* @param children Optional list of Nodes or strings.
|
|
40
|
+
* @returns The newly created HTMLDivElement.
|
|
41
|
+
*/
|
|
42
|
+
const div = (
|
|
43
|
+
className?: string,
|
|
44
|
+
...children: (Node | string)[]
|
|
45
|
+
): HTMLDivElement => {
|
|
46
|
+
const node: HTMLDivElement = doc().createElement('div')
|
|
47
|
+
if (className) node.classList.add(className)
|
|
48
|
+
node.append(...children)
|
|
49
|
+
return node
|
|
50
|
+
}
|
|
96
51
|
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
52
|
+
/**
|
|
53
|
+
* # Parse
|
|
54
|
+
* @param html HTML string.
|
|
55
|
+
* @returns Parsed node.
|
|
56
|
+
*/
|
|
57
|
+
const parse = (html: string): Node => {
|
|
58
|
+
const node: HTMLDivElement = div()
|
|
59
|
+
node.innerHTML = html
|
|
60
|
+
return node.firstChild as Node
|
|
61
|
+
}
|
|
105
62
|
|
|
106
|
-
/**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const newNsText = div('nst', text)
|
|
117
|
-
if (oldNsText) {
|
|
118
|
-
oldNsText.replaceWith(newNsText)
|
|
119
|
-
} else {
|
|
120
|
-
ns.insertBefore(newNsText, ns.firstChild)
|
|
63
|
+
/**
|
|
64
|
+
* # Make Nanosplash Element
|
|
65
|
+
* @returns Nanpslash DOM element.
|
|
66
|
+
*/
|
|
67
|
+
const makeNs = (): NSElement => {
|
|
68
|
+
const circle: string = '<circle class=path cx=25 cy=25 r=20 fill=none/>'
|
|
69
|
+
const svg = parse(`<svg viewBox="0 0 50 50">${circle}</svg>`) as Element
|
|
70
|
+
const node = div('ns', div('nst'), div('nss', svg)) as NSElement
|
|
71
|
+
node.nsId = Date.now()
|
|
72
|
+
return node
|
|
121
73
|
}
|
|
122
|
-
}
|
|
123
74
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
75
|
+
/**
|
|
76
|
+
* # Peek Nanosplash Queue
|
|
77
|
+
* Collect all Nanosplash elements in the DOM, sort them by their NS ID
|
|
78
|
+
* in ascending order, and return the first element.
|
|
79
|
+
* @returns The front of the queue.
|
|
80
|
+
*/
|
|
81
|
+
const peekNsQueue = (): NSElement | null =>
|
|
82
|
+
getAllNs().sort((a: NSElement, b: NSElement) => a.nsId - b.nsId)[0] ?? null
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* # Set Nanosplash Text
|
|
86
|
+
* Replace the text node to trigger the animation which in turn is invoked
|
|
87
|
+
* by the connected callback in the DOM.
|
|
88
|
+
* @param ns Nanosplash element.
|
|
89
|
+
* @param text Text to display adjacent to spinner.
|
|
90
|
+
*/
|
|
91
|
+
const setNsText = (ns: NSElement, text: string): void => {
|
|
92
|
+
const oldNsText = first(ns, '.nst') as Element | null
|
|
93
|
+
if (!text) return oldNsText?.remove()
|
|
94
|
+
const newNsText = div('nst', text)
|
|
95
|
+
if (oldNsText) {
|
|
96
|
+
oldNsText.replaceWith(newNsText)
|
|
97
|
+
} else {
|
|
98
|
+
ns.insertBefore(newNsText, ns.firstChild)
|
|
99
|
+
}
|
|
134
100
|
}
|
|
135
|
-
parent.append(ns)
|
|
136
|
-
parent.classList.add('nsh')
|
|
137
|
-
}
|
|
138
101
|
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
ns = recycledNs as NSElement
|
|
153
|
-
} else {
|
|
154
|
-
ns = makeNs()
|
|
155
|
-
setNsParent(ns, parent as Element)
|
|
102
|
+
/**
|
|
103
|
+
* # Set Nanosplash Parent
|
|
104
|
+
* Define where inside the DOM to spawn the Nansoplash.
|
|
105
|
+
* @param ns Nanosplash element.
|
|
106
|
+
* @param parent NS element's parent to be.
|
|
107
|
+
*/
|
|
108
|
+
const setNsParent = (ns: NSElement, parent: Element): void => {
|
|
109
|
+
const child = parent.firstElementChild
|
|
110
|
+
if (child) {
|
|
111
|
+
parent.insertBefore(ns, child)
|
|
112
|
+
}
|
|
113
|
+
parent.append(ns)
|
|
114
|
+
parent.classList.add('nsh')
|
|
156
115
|
}
|
|
157
|
-
setNsText(ns, text ?? '')
|
|
158
|
-
const top: string = scrollY + 'px'
|
|
159
|
-
bod.style.setProperty('--ns-top', top)
|
|
160
|
-
return ns.nsId
|
|
161
|
-
}
|
|
162
116
|
|
|
163
|
-
/**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
117
|
+
/**
|
|
118
|
+
* # Show Nanosplash
|
|
119
|
+
* @param text Text to display adjacent to spinner.
|
|
120
|
+
* @param inside Selector or element in which the NS element will be spawned.
|
|
121
|
+
* @returns The ID if the NS element — which is a UTC integer.
|
|
122
|
+
*/
|
|
123
|
+
const show = (text?: string, inside?: string | Element): number | null => {
|
|
124
|
+
const parent: Element | null = (
|
|
125
|
+
inside ? parseRef(inside) : bod
|
|
126
|
+
) as Element | null
|
|
127
|
+
let ns: NSElement
|
|
128
|
+
const recycledNs = first(parent ?? bod(), '& > .ns')
|
|
129
|
+
if (recycledNs) {
|
|
130
|
+
ns = recycledNs as NSElement
|
|
131
|
+
} else {
|
|
132
|
+
ns = makeNs()
|
|
133
|
+
setNsParent(ns, parent as Element)
|
|
134
|
+
}
|
|
135
|
+
setNsText(ns, text ?? '')
|
|
136
|
+
const top: string = scrollY + 'px'
|
|
137
|
+
bod().style.setProperty('--ns-top', top)
|
|
138
|
+
return ns.nsId
|
|
139
|
+
}
|
|
171
140
|
|
|
172
|
-
/**
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
141
|
+
/**
|
|
142
|
+
* # Remove Nanosplash
|
|
143
|
+
* @param ns Nanosplash elememnt.
|
|
144
|
+
*/
|
|
145
|
+
const removeNs = (ns?: Element | null): void => {
|
|
146
|
+
ns?.parentElement?.classList.remove('nsh')
|
|
147
|
+
ns?.remove()
|
|
148
|
+
}
|
|
178
149
|
|
|
179
|
-
/**
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
150
|
+
/**
|
|
151
|
+
* # Find Nanosplash
|
|
152
|
+
* @param id The UTC integer returned from the `show` function.
|
|
153
|
+
* @returns Null or the corresponding Nanosplash element.
|
|
154
|
+
*/
|
|
155
|
+
const findNs = (id: number) => getAllNs().find(v => v.nsId === id) ?? null
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* # Hide Nanosplash
|
|
159
|
+
* Hide agnostically in FIFO order, specifically by ID, or all by the asterisk
|
|
160
|
+
* which will delete all Nanosplashes.
|
|
161
|
+
* @param id Optional ID of a Nanosplash element or '*' .
|
|
162
|
+
*/
|
|
163
|
+
const hide = (id?: number | '*'): void => {
|
|
164
|
+
if (id === '*') all(doc(), '.ns').forEach(removeNs)
|
|
165
|
+
else removeNs(typeof id === 'number' ? findNs(id) : peekNsQueue())
|
|
166
|
+
}
|
|
189
167
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const addCssToBody = (): void => {
|
|
194
|
-
get('#' + styleId)?.remove()
|
|
195
|
-
bod.append(parse(`<style id=${styleId}>${style}</style>`))
|
|
196
|
-
}
|
|
168
|
+
// Add CSS to window
|
|
169
|
+
first(doc(), '#ns')?.remove()
|
|
170
|
+
bod().append(parse(`<style id="ns">${style}</style>`))
|
|
197
171
|
|
|
198
|
-
|
|
199
|
-
* # Use Nanosplash
|
|
200
|
-
* @returns Nanosplash API.
|
|
201
|
-
*/
|
|
202
|
-
export const useNs = (): NanosplashInterface => {
|
|
203
|
-
addCssToBody()
|
|
204
|
-
return (window.ns = {
|
|
172
|
+
return {
|
|
205
173
|
show,
|
|
206
174
|
hide,
|
|
207
175
|
version,
|
|
208
|
-
}
|
|
176
|
+
}
|
|
209
177
|
}
|
package/src/ts/main.ts
CHANGED
package/src/ts/types/Types.ts
CHANGED
|
@@ -5,19 +5,6 @@ export type UTCInteger = Integer
|
|
|
5
5
|
export type DOMSelector = string
|
|
6
6
|
export type ElementReference = DOMSelector | Element
|
|
7
7
|
|
|
8
|
-
export interface ScopedSelectors {
|
|
9
|
-
/**
|
|
10
|
-
* @param selector Selector to match with a DOM element.
|
|
11
|
-
* @returns An array of elements matching with the selector.
|
|
12
|
-
*/
|
|
13
|
-
all: (selector: DOMSelector) => Element[]
|
|
14
|
-
/**
|
|
15
|
-
* @param selector Selector to match with a DOM element.
|
|
16
|
-
* @returns Null or the first element in the DOM to match the selector.
|
|
17
|
-
*/
|
|
18
|
-
first: (selector: DOMSelector) => Element | null
|
|
19
|
-
}
|
|
20
|
-
|
|
21
8
|
export interface NSElement extends HTMLDivElement {
|
|
22
9
|
nsId: number
|
|
23
10
|
}
|
package/tests/Nanosplash.spec.ts
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import { describe, it,
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
2
2
|
import { JSDOM } from 'jsdom'
|
|
3
|
-
import {
|
|
3
|
+
import { useNs } from '../src/ts/Nanosplash'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
async function updateGlobals() {
|
|
10
|
-
dom = new JSDOM()
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
globalThis.window = dom.window
|
|
13
|
-
document = globalThis.document = dom.window.document
|
|
14
|
-
ns = globalThis.window.ns = (await import('../src/ts/Nanosplash')).useNs()
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
beforeEach(updateGlobals)
|
|
5
|
+
const dom = new JSDOM()
|
|
6
|
+
var window = dom.window
|
|
7
|
+
const ns = (window.ns = useNs(window))
|
|
18
8
|
|
|
19
9
|
describe('Nanosplash API', () => {
|
|
20
10
|
it('should be defined', () => {
|
package/dist/cjs/ns.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b='@keyframes nsRotate{to{transform:rotate(360deg)}}@keyframes nsDash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes nsFade{0%{opacity:0}to{opacity:1}}@keyframes nsAscend{0%{opacity:0;transform:translateY(13px)}to{opacity:1;transform:translateY(0)}}:root{--ns-top: 0px}.ns,body.nsh,body.nsh:before,.nsh:before{width:100%;height:100%}.ns,.nsh:before{bottom:0;right:0}.ns{display:flex;justify-content:center;align-items:center}.nsh{--color: DarkSlateGray;--size: 20px;--relSize: calc(var(--size) * .9);--font: "Helvetica", "Arial", sans-serif;--weight: 400;--bg: rgba(255, 255, 255, .9);--zIdx: 999999999;--blur: blur(5px)}.nsh{position:relative;z-index:var(--zIdx)}.nsh:before{position:absolute;background-color:var(--bg);content:"";backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);z-index:calc(var(--zIdx) + 1);border-radius:inherit}body.nsh,body.nsh:before{position:fixed;top:var(--ns-top);left:0}.ns{position:absolute;z-index:calc(var(--zIdx) + 2);animation:nsFade 2s;gap:var(--relSize)}.nst{color:var(--color);font-size:var(--size);font-family:var(--font);font-weight:var(--weight);max-width:80dvw;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-shadow:0 0 .06rem rgba(47,79,79,.25);filter:drop-shadow(0 0 .07rem rgba(0,0,0,.25));animation:nsAscend .5s}.nss{display:block;width:var(--relSize);height:var(--relSize);animation:nsAscend .5s}.nss>svg{animation:nsRotate 2s linear infinite;position:relative;width:inherit;height:inherit;stroke-width:8}.nss .path{stroke:var(--color);stroke-linecap:round;animation:nsDash 1.5s ease-in-out infinite}',m="3.1.1",l="ns",i=document,r=i.body,a=e=>(s=>({all:s,first:t=>s(t)[0]??null}))(s=>Array.from(e.querySelectorAll(s))),f=e=>a(i).all(e),h=e=>a(i).first(e),p=()=>f(".ns"),u=e=>e instanceof Element?e:h(e),n=(e,...s)=>{const t=i.createElement("div");return e&&t.classList.add(e),t.append(...s),t},v=e=>{const s=n();return s.innerHTML=e,s.firstChild},g=()=>{const s=v('<svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none /></svg>'),t=n("ns",n("nst"),n("nss",s));return t.nsId=Date.now(),t},w=()=>p().sort((e,s)=>e.nsId-s.nsId)[0]??null,k=(e,s)=>{const t=a(e).first(".nst");if(!s)return t==null?void 0:t.remove();const o=n("nst",s);t?t.replaceWith(o):e.insertBefore(o,e.firstChild)},x=(e,s)=>{const t=s.firstElementChild;t&&s.insertBefore(e,t),s.append(e),s.classList.add("nsh")},z=(e,s)=>{const t=s?u(s):r;let o;const c=a(t??r).first("& > .ns");c?o=c:(o=g(),x(o,t)),k(o,e??"");const y=scrollY+"px";return r.style.setProperty("--ns-top",y),o.nsId},d=e=>{var s;(s=e==null?void 0:e.parentElement)==null||s.classList.remove("nsh"),e==null||e.remove()},I=e=>p().find(s=>s.nsId===e)??null,N=e=>{e==="*"?f(".ns").forEach(d):d(typeof e=="number"?I(e):w())},A=()=>{var e;(e=h("#"+l))==null||e.remove(),r.append(v(`<style id=${l}>${b}</style>`))},S=()=>(A(),window.ns={show:z,hide:N,version:m});exports.useNs=S;
|
package/dist/es/ns.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
const b = '@keyframes nsRotate{to{transform:rotate(360deg)}}@keyframes nsDash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes nsFade{0%{opacity:0}to{opacity:1}}@keyframes nsAscend{0%{opacity:0;transform:translateY(13px)}to{opacity:1;transform:translateY(0)}}:root{--ns-top: 0px}.ns,body.nsh,body.nsh:before,.nsh:before{width:100%;height:100%}.ns,.nsh:before{bottom:0;right:0}.ns{display:flex;justify-content:center;align-items:center}.nsh{--color: DarkSlateGray;--size: 20px;--relSize: calc(var(--size) * .9);--font: "Helvetica", "Arial", sans-serif;--weight: 400;--bg: rgba(255, 255, 255, .9);--zIdx: 999999999;--blur: blur(5px)}.nsh{position:relative;z-index:var(--zIdx)}.nsh:before{position:absolute;background-color:var(--bg);content:"";backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);z-index:calc(var(--zIdx) + 1);border-radius:inherit}body.nsh,body.nsh:before{position:fixed;top:var(--ns-top);left:0}.ns{position:absolute;z-index:calc(var(--zIdx) + 2);animation:nsFade 2s;gap:var(--relSize)}.nst{color:var(--color);font-size:var(--size);font-family:var(--font);font-weight:var(--weight);max-width:80dvw;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-shadow:0 0 .06rem rgba(47,79,79,.25);filter:drop-shadow(0 0 .07rem rgba(0,0,0,.25));animation:nsAscend .5s}.nss{display:block;width:var(--relSize);height:var(--relSize);animation:nsAscend .5s}.nss>svg{animation:nsRotate 2s linear infinite;position:relative;width:inherit;height:inherit;stroke-width:8}.nss .path{stroke:var(--color);stroke-linecap:round;animation:nsDash 1.5s ease-in-out infinite}', m = "3.1.1", l = "ns", i = document, r = i.body, a = (e) => /* @__PURE__ */ ((s) => ({
|
|
2
|
-
all: s,
|
|
3
|
-
first: (t) => s(t)[0] ?? null
|
|
4
|
-
}))((s) => Array.from(e.querySelectorAll(s))), f = (e) => a(i).all(e), h = (e) => a(i).first(e), p = () => f(".ns"), u = (e) => e instanceof Element ? e : h(e), n = (e, ...s) => {
|
|
5
|
-
const t = i.createElement("div");
|
|
6
|
-
return e && t.classList.add(e), t.append(...s), t;
|
|
7
|
-
}, v = (e) => {
|
|
8
|
-
const s = n();
|
|
9
|
-
return s.innerHTML = e, s.firstChild;
|
|
10
|
-
}, g = () => {
|
|
11
|
-
const s = v('<svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none /></svg>'), t = n("ns", n("nst"), n("nss", s));
|
|
12
|
-
return t.nsId = Date.now(), t;
|
|
13
|
-
}, w = () => p().sort((e, s) => e.nsId - s.nsId)[0] ?? null, k = (e, s) => {
|
|
14
|
-
const t = a(e).first(".nst");
|
|
15
|
-
if (!s)
|
|
16
|
-
return t == null ? void 0 : t.remove();
|
|
17
|
-
const o = n("nst", s);
|
|
18
|
-
t ? t.replaceWith(o) : e.insertBefore(o, e.firstChild);
|
|
19
|
-
}, x = (e, s) => {
|
|
20
|
-
const t = s.firstElementChild;
|
|
21
|
-
t && s.insertBefore(e, t), s.append(e), s.classList.add("nsh");
|
|
22
|
-
}, z = (e, s) => {
|
|
23
|
-
const t = s ? u(s) : r;
|
|
24
|
-
let o;
|
|
25
|
-
const c = a(t ?? r).first("& > .ns");
|
|
26
|
-
c ? o = c : (o = g(), x(o, t)), k(o, e ?? "");
|
|
27
|
-
const y = scrollY + "px";
|
|
28
|
-
return r.style.setProperty("--ns-top", y), o.nsId;
|
|
29
|
-
}, d = (e) => {
|
|
30
|
-
var s;
|
|
31
|
-
(s = e == null ? void 0 : e.parentElement) == null || s.classList.remove("nsh"), e == null || e.remove();
|
|
32
|
-
}, I = (e) => p().find((s) => s.nsId === e) ?? null, A = (e) => {
|
|
33
|
-
e === "*" ? f(".ns").forEach(d) : d(typeof e == "number" ? I(e) : w());
|
|
34
|
-
}, N = () => {
|
|
35
|
-
var e;
|
|
36
|
-
(e = h("#" + l)) == null || e.remove(), r.append(v(`<style id=${l}>${b}</style>`));
|
|
37
|
-
}, S = () => (N(), window.ns = {
|
|
38
|
-
show: z,
|
|
39
|
-
hide: A,
|
|
40
|
-
version: m
|
|
41
|
-
});
|
|
42
|
-
export {
|
|
43
|
-
S as useNs
|
|
44
|
-
};
|
package/dist/iife/ns.iife.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(){"use strict";const y='@keyframes nsRotate{to{transform:rotate(360deg)}}@keyframes nsDash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes nsFade{0%{opacity:0}to{opacity:1}}@keyframes nsAscend{0%{opacity:0;transform:translateY(13px)}to{opacity:1;transform:translateY(0)}}:root{--ns-top: 0px}.ns,body.nsh,body.nsh:before,.nsh:before{width:100%;height:100%}.ns,.nsh:before{bottom:0;right:0}.ns{display:flex;justify-content:center;align-items:center}.nsh{--color: DarkSlateGray;--size: 20px;--relSize: calc(var(--size) * .9);--font: "Helvetica", "Arial", sans-serif;--weight: 400;--bg: rgba(255, 255, 255, .9);--zIdx: 999999999;--blur: blur(5px)}.nsh{position:relative;z-index:var(--zIdx)}.nsh:before{position:absolute;background-color:var(--bg);content:"";backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);z-index:calc(var(--zIdx) + 1);border-radius:inherit}body.nsh,body.nsh:before{position:fixed;top:var(--ns-top);left:0}.ns{position:absolute;z-index:calc(var(--zIdx) + 2);animation:nsFade 2s;gap:var(--relSize)}.nst{color:var(--color);font-size:var(--size);font-family:var(--font);font-weight:var(--weight);max-width:80dvw;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-shadow:0 0 .06rem rgba(47,79,79,.25);filter:drop-shadow(0 0 .07rem rgba(0,0,0,.25));animation:nsAscend .5s}.nss{display:block;width:var(--relSize);height:var(--relSize);animation:nsAscend .5s}.nss>svg{animation:nsRotate 2s linear infinite;position:relative;width:inherit;height:inherit;stroke-width:8}.nss .path{stroke:var(--color);stroke-linecap:round;animation:nsDash 1.5s ease-in-out infinite}',b="3.1.1",c="ns",r=document,i=r.body,a=e=>(s=>({all:s,first:t=>s(t)[0]??null}))(s=>Array.from(e.querySelectorAll(s))),l=e=>a(r).all(e),d=e=>a(r).first(e),f=()=>l(".ns"),m=e=>e instanceof Element?e:d(e),o=(e,...s)=>{const t=r.createElement("div");return e&&t.classList.add(e),t.append(...s),t},h=e=>{const s=o();return s.innerHTML=e,s.firstChild},u=()=>{const s=h('<svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none /></svg>'),t=o("ns",o("nst"),o("nss",s));return t.nsId=Date.now(),t},g=()=>f().sort((e,s)=>e.nsId-s.nsId)[0]??null,w=(e,s)=>{const t=a(e).first(".nst");if(!s)return t==null?void 0:t.remove();const n=o("nst",s);t?t.replaceWith(n):e.insertBefore(n,e.firstChild)},k=(e,s)=>{const t=s.firstElementChild;t&&s.insertBefore(e,t),s.append(e),s.classList.add("nsh")},x=(e,s)=>{const t=s?m(s):i;let n;const v=a(t??i).first("& > .ns");v?n=v:(n=u(),k(n,t)),w(n,e??"");const A=scrollY+"px";return i.style.setProperty("--ns-top",A),n.nsId},p=e=>{var s;(s=e==null?void 0:e.parentElement)==null||s.classList.remove("nsh"),e==null||e.remove()},z=e=>f().find(s=>s.nsId===e)??null,I=e=>{e==="*"?l(".ns").forEach(p):p(typeof e=="number"?z(e):g())},N=()=>{var e;(e=d("#"+c))==null||e.remove(),i.append(h(`<style id=${c}>${y}</style>`))};N(),window.ns={show:x,hide:I,version:b}})();
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { ref, onMounted } from 'vue'
|
|
3
|
-
|
|
4
|
-
onMounted(async () => {
|
|
5
|
-
if (!window) return
|
|
6
|
-
const nsLib = await import('../../../../dist/es/ns.js')
|
|
7
|
-
const ns = nsLib.useNs()
|
|
8
|
-
|
|
9
|
-
const Commands = {
|
|
10
|
-
ShowInsideA: 'ns.show("Loading A", "#a")',
|
|
11
|
-
ShowInsideB: 'ns.show("Loading B", "#b")',
|
|
12
|
-
ShowInsideC: 'ns.show("Loading C", "#c")',
|
|
13
|
-
ShowInsideD: 'ns.show("Loading D", "#d")',
|
|
14
|
-
ShowInsideWrapper: 'ns.show("Loading Wrapper", "#wrapper")',
|
|
15
|
-
ShowFullScreen: 'ns.show("Loading window")',
|
|
16
|
-
Progress: 'Progressive Demo',
|
|
17
|
-
Hide: 'ns.hide()',
|
|
18
|
-
HideAll: 'ns.hide("*")',
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const rCommandString = ref('')
|
|
22
|
-
|
|
23
|
-
const wait = ms => new Promise(r => setTimeout(r, ms))
|
|
24
|
-
|
|
25
|
-
async function onClickExe() {
|
|
26
|
-
const value = rCommandString.value
|
|
27
|
-
const phrases = [
|
|
28
|
-
'Generating witty dialog',
|
|
29
|
-
'Swapping time and space',
|
|
30
|
-
'sudo rm -rf /**/*',
|
|
31
|
-
'Tokenizing real life',
|
|
32
|
-
'Pushing pixels',
|
|
33
|
-
"Don't think of purple hippos",
|
|
34
|
-
'One mississippi, two mississippi...',
|
|
35
|
-
]
|
|
36
|
-
switch (value) {
|
|
37
|
-
case Commands.ShowInsideA:
|
|
38
|
-
ns.show('Loading A', '#a')
|
|
39
|
-
break
|
|
40
|
-
case Commands.ShowInsideB:
|
|
41
|
-
ns.show('Loading B', '#b')
|
|
42
|
-
break
|
|
43
|
-
case Commands.ShowInsideC:
|
|
44
|
-
ns.show('Loading C', '#c')
|
|
45
|
-
break
|
|
46
|
-
case Commands.ShowInsideD:
|
|
47
|
-
ns.show('Loading D', '#d')
|
|
48
|
-
break
|
|
49
|
-
case Commands.ShowInsideWrapper:
|
|
50
|
-
ns.show('Loading Wrapper', '#wrapper')
|
|
51
|
-
break
|
|
52
|
-
case Commands.ShowFullScreen:
|
|
53
|
-
const id = ns.show('Loading window')
|
|
54
|
-
await wait(4000)
|
|
55
|
-
ns.hide(id)
|
|
56
|
-
break
|
|
57
|
-
case Commands.Hide:
|
|
58
|
-
ns.hide()
|
|
59
|
-
break
|
|
60
|
-
case Commands.HideAll:
|
|
61
|
-
ns.hide('*')
|
|
62
|
-
break
|
|
63
|
-
case Commands.Progress:
|
|
64
|
-
for (const phrase of phrases) {
|
|
65
|
-
ns.show(phrase)
|
|
66
|
-
await wait(1500)
|
|
67
|
-
}
|
|
68
|
-
ns.hide('*')
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
</script>
|
|
73
|
-
|
|
74
|
-
<template>
|
|
75
|
-
<div class="container">
|
|
76
|
-
<select class="select" v-model="rCommandString">
|
|
77
|
-
<option value="" selected disabled>Click and select</option>
|
|
78
|
-
<option v-for="(command, i) in Commands" :key="i" :value="command">
|
|
79
|
-
{{ command }}
|
|
80
|
-
</option>
|
|
81
|
-
</select>
|
|
82
|
-
<div class="exe" @click="onClickExe">Run</div>
|
|
83
|
-
</div>
|
|
84
|
-
</template>
|
|
85
|
-
|
|
86
|
-
<style lang="sass" scoped>
|
|
87
|
-
@use "sass:color"
|
|
88
|
-
|
|
89
|
-
$border-radius: 5px
|
|
90
|
-
.container
|
|
91
|
-
position: relative
|
|
92
|
-
display: flex
|
|
93
|
-
border-radius: $border-radius
|
|
94
|
-
z-index: 1
|
|
95
|
-
& > *
|
|
96
|
-
padding: 10px 20px
|
|
97
|
-
|
|
98
|
-
.select
|
|
99
|
-
position: relative
|
|
100
|
-
display: flex
|
|
101
|
-
flex-grow: 1
|
|
102
|
-
font-family: monospace
|
|
103
|
-
font-size: 14px
|
|
104
|
-
background-color: var(--vp-c-bg-alt)
|
|
105
|
-
border-radius: $border-radius 0 0 $border-radius
|
|
106
|
-
border: 1px solid rgba(Black, 0.1)
|
|
107
|
-
cursor: pointer
|
|
108
|
-
width: 100%
|
|
109
|
-
|
|
110
|
-
$btn-bg: RoyalBlue
|
|
111
|
-
.exe
|
|
112
|
-
position: relative
|
|
113
|
-
display: inline-flex
|
|
114
|
-
color: White
|
|
115
|
-
background-color: $btn-bg
|
|
116
|
-
cursor: pointer
|
|
117
|
-
border-radius: 0 $border-radius $border-radius 0
|
|
118
|
-
border: 1px solid rgba(Black, 0.1)
|
|
119
|
-
&:hover
|
|
120
|
-
background-color: darken($btn-bg, 10%)
|
|
121
|
-
</style>
|