jabroni-outfit 1.4.9 → 1.6.5

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.
@@ -1,38 +1,89 @@
1
- import type { Scheme } from "./types";
2
-
3
- export const DefaultScheme: Scheme = {
4
- excludeFilter: [
5
- { type: "checkbox", model: "state.filterExclude", label: "exclude" },
6
- { type: "text", model: "state.filterExcludeWords", placeholder: "word, word1|word2, f:full_word..." }
7
- ],
8
- includeFilter: [
9
- { type: "checkbox", model: "state.filterInclude", label: "include" },
10
- { type: "text", model: "state.filterIncludeWords", placeholder: "word, word1|word2, f:full_word..." }
11
- ],
12
- infiniteScroll: [
13
- { type: "checkbox", model: "state.infiniteScrollEnabled", label: "infinite scroll" },
14
- {
15
- type: "span", innerText:
16
- "return `${stateLocale.pagIndexCur}/${stateLocale.pagIndexLast}`", "v-if": "return stateLocale.pagIndexLast > 1"
17
- }
18
- ],
19
- durationFilter: [
20
- { type: "checkbox", model: "state.filterDuration", label: "duration" },
21
- { type: "number", model: "state.filterDurationFrom", step: "10", min: "0", max: "72000", labelBefore: "from" },
22
- { type: "number", model: "state.filterDurationTo", step: "10", min: "0", max: "72000", labelBefore: "to" }
23
- ],
24
- }
25
-
26
- export const extendDefaultScheme = (newScheme: Scheme) =>
27
- Object.entries(DefaultScheme).reduce((acc, [k, v], i) => {
28
- if (i === 2) Object.assign(acc, newScheme);
29
- Object.assign(acc, { [k]: v });
30
- return acc;
31
- }, {});
32
-
33
- export const defaultSchemeWithPrivateFilter = extendDefaultScheme({
34
- privateFilter: [
35
- { type: "checkbox", model: "state.filterPrivate", label: "private" },
36
- { type: "checkbox", model: "state.filterPublic", label: "public" }
37
- ]
38
- });
1
+ import type { Scheme } from "./types";
2
+
3
+ export const DefaultScheme: Scheme = {
4
+ excludeFilter: [
5
+ { type: "checkbox", model: "state.filterExclude", label: "exclude" },
6
+ { type: "text", model: "state.filterExcludeWords", placeholder: "word, word1|word2, f:full_word..." }
7
+ ],
8
+ includeFilter: [
9
+ { type: "checkbox", model: "state.filterInclude", label: "include" },
10
+ { type: "text", model: "state.filterIncludeWords", placeholder: "word, word1|word2, f:full_word..." }
11
+ ],
12
+ infiniteScroll: [
13
+ { type: "checkbox", model: "state.infiniteScrollEnabled", label: "infinite scroll" },
14
+ {
15
+ type: "span", innerText:
16
+ "return `${localState.pagIndexCur}/${localState.pagIndexLast}`", "v-if": "return localState.pagIndexLast > 1"
17
+ }
18
+ ],
19
+ durationFilter: [
20
+ { type: "checkbox", model: "state.filterDuration", label: "duration" },
21
+ { type: "number", model: "state.filterDurationFrom", step: "10", min: "0", max: "72000", labelBefore: "from" },
22
+ { type: "number", model: "state.filterDurationTo", step: "10", min: "0", max: "72000", labelBefore: "to" }
23
+ ],
24
+ }
25
+
26
+ export const customScheme: Scheme = {
27
+ sortFilter: [
28
+ {
29
+ type: "span", innerText: 'sort by:'
30
+ },
31
+ {
32
+ type: 'button',
33
+ innerText: 'views',
34
+ callback: () => {
35
+ //@ts-ignore
36
+ window.sortByViews?.();
37
+ },
38
+ },
39
+ {
40
+ type: 'button',
41
+ innerText: 'duration',
42
+ callback: () => {
43
+ //@ts-ignore
44
+ window.sortByDuration?.();
45
+ },
46
+ }],
47
+
48
+ privacyFilter: [
49
+ { type: "checkbox", model: "state.filterPrivate", label: "private" },
50
+ { type: "checkbox", model: "state.filterPublic", label: "public" }
51
+ ],
52
+
53
+ privacyAccess: [
54
+ { type: "checkbox", model: "state.autoRequestAccess", label: "auto friend request" },
55
+ {
56
+ type: 'button',
57
+ innerText: 'check access 🔓',
58
+ callback: () => {
59
+ //@ts-ignore
60
+ window.requestAccess?.();
61
+ }
62
+ }
63
+ ],
64
+
65
+ hdFilter: [
66
+ { type: "checkbox", model: "state.filterHD", label: "HD" },
67
+ ]
68
+ }
69
+
70
+ export const extendScheme = (scheme: Scheme, newScheme: Scheme) =>
71
+ Object.entries(scheme).reduce((acc, [k, v], i) => {
72
+ if (i === 2) Object.assign(acc, newScheme);
73
+ Object.assign(acc, { [k]: v });
74
+ return acc;
75
+ }, {});
76
+
77
+ export const defaultSchemeWithPrivacyFilter = extendScheme(DefaultScheme, {
78
+ privacyFilter: customScheme.privacyFilter,
79
+ privacyAccess: customScheme.privacyAccess
80
+ });
81
+
82
+ export const defaultSchemeWithPrivacyFilterWithHD = extendScheme(defaultSchemeWithPrivacyFilter, {
83
+ hdFilter: customScheme.hdFilter
84
+ });
85
+
86
+ export const defaultSchemeWithPrivacyFilterWithHDwithSort = extendScheme(defaultSchemeWithPrivacyFilterWithHD, {
87
+ sortFilter: customScheme.sortFilter
88
+ });
89
+
package/src/ui/index.ts CHANGED
@@ -1,29 +1,31 @@
1
- import { createApp } from "vue";
2
- import { DefaultScheme } from "./default-scheme";
3
- import type { Scheme, UIPosition } from "./types";
4
- import type { JabroniOutfitStore } from "../store/store";
5
- import App from "./vue-templates/App.vue"
6
- import { parseDom } from "billy-herrington-utils";
7
-
8
- export class JabroniOutfitUI {
9
- private getRoot(rootSelector: string | undefined) {
10
- let root: string | undefined = rootSelector;
11
- if (!root) {
12
- const rootEl = parseDom('<div id="tapermonkey-app" style="position: relative; z-index: 999999;"></div>');
13
- document.body.appendChild(rootEl);
14
- root = "#tapermonkey-app";
15
- }
16
- document.querySelector(root)?.classList.add('taper-class');
17
- return root;
18
- }
19
-
20
- constructor(
21
- { state, stateLocale }: JabroniOutfitStore,
22
- scheme: Scheme = DefaultScheme,
23
- rootSelector?: string,
24
- position: UIPosition = { fixed: true, right: true, bottom: true }
25
- ) {
26
- const app = createApp(App, { state, stateLocale, scheme, position });
27
- app.mount(this.getRoot(rootSelector));
28
- }
29
- }
1
+ import { createApp } from "vue";
2
+ import { DefaultScheme } from "./default-scheme";
3
+ import type { Scheme, UIPosition } from "./types";
4
+ import type { JabroniOutfitStore } from "../store/store";
5
+ import App from "./vue-templates/App.vue"
6
+ import { parseDom } from "billy-herrington-utils";
7
+
8
+ const DEFAULT_ROOT = 'jabroni-outfit-root';
9
+
10
+ export class JabroniOutfitUI {
11
+ public app: ReturnType<typeof createApp>;
12
+
13
+ private getRoot(rootSelector: string) {
14
+ if (rootSelector === DEFAULT_ROOT) {
15
+ const rootEl = parseDom(`<div id="${rootSelector}" style="position: relative; z-index: 999999;"></div>`);
16
+ document.body.appendChild(rootEl);
17
+ }
18
+ document.getElementById(rootSelector)?.classList.add('taper-class');
19
+ return `#${rootSelector}`;
20
+ }
21
+
22
+ constructor(
23
+ { state, localState }: JabroniOutfitStore,
24
+ scheme: Scheme = DefaultScheme,
25
+ rootSelector = DEFAULT_ROOT,
26
+ position: UIPosition = { fixed: true, right: true, bottom: true }
27
+ ) {
28
+ this.app = createApp(App, { state, localState, scheme, position });
29
+ this.app.mount(this.getRoot(rootSelector));
30
+ }
31
+ }
package/src/ui/types.ts CHANGED
@@ -1,27 +1,27 @@
1
- export interface SchemeRowEl {
2
- type: 'checkbox' | 'text' | 'number' | 'span' | 'button';
3
- model?: string,
4
- label?: string,
5
- labelBefore?: string,
6
- innerText?: string,
7
- max?: string,
8
- min?: string,
9
- step?: string,
10
- "v-if"?: string,
11
- placeholder?: string
12
- callback?: () => void
13
- }
14
-
15
- export type SchemeRow = SchemeRowEl[];
16
-
17
- export interface Scheme {
18
- [key: string]: SchemeRow
19
- }
20
-
21
- export interface UIPosition {
22
- fixed: boolean,
23
- left?: boolean,
24
- right?: boolean,
25
- top?: boolean,
26
- bottom?: boolean
27
- }
1
+ export interface SchemeRowEl {
2
+ type: 'checkbox' | 'text' | 'number' | 'span' | 'button';
3
+ model?: string,
4
+ label?: string,
5
+ labelBefore?: string,
6
+ innerText?: string,
7
+ max?: string,
8
+ min?: string,
9
+ step?: string,
10
+ "v-if"?: string,
11
+ placeholder?: string
12
+ callback?: () => void
13
+ }
14
+
15
+ export type SchemeRow = SchemeRowEl[];
16
+
17
+ export interface Scheme {
18
+ [key: string]: SchemeRow
19
+ }
20
+
21
+ export interface UIPosition {
22
+ fixed: boolean,
23
+ left?: boolean,
24
+ right?: boolean,
25
+ top?: boolean,
26
+ bottom?: boolean
27
+ }
@@ -1,48 +1,48 @@
1
- <script setup lang="ts">
2
- import Config from './icons/Config.vue';
3
- import Close from './icons/Close.vue';
4
- import Gen from './Gen.vue';
5
- import type { Scheme, UIPosition } from '../types';
6
- import type { Reactive } from 'vue';
7
- import type { RecordV } from '../../store/types';
8
-
9
- const { state, stateLocale, scheme, position } = defineProps<{
10
- state: Reactive<RecordV>,
11
- stateLocale: Reactive<RecordV>,
12
- scheme?: Scheme,
13
- position: UIPosition
14
- }>();
15
-
16
- const optClasses = {
17
- fixed: 'fixed',
18
- right: 'right-0',
19
- left: 'left-0',
20
- top: 'top-0',
21
- bottom: 'bottom-0'
22
- }
23
-
24
- const pos = Object.entries(position).filter(([_, v]) => v)
25
- .map(([k, _]) => optClasses[k]).join(' ');
26
-
27
- </script>
28
- <template>
29
- <div class="z-9999 rounded bg-zinc-800 max-w-full p-2 m-2"
30
- :class="`${state.hidden ? 'hover:bg-gray-600' : ''} ${pos}`" v-if="state.uiEnabled">
31
-
32
- <div class="flex items-center cursor-pointer py-1 px-2 m-1 rounded"
33
- :class="!state.hidden ? 'hover:bg-zinc-900' : ''" @click="state.hidden = !state.hidden">
34
- <span class="m-auto flex mono">
35
- <span v-if="state.hidden && stateLocale.pagIndexLast as number > 1"
36
- class="px-3 py-2 mr-2 bg-gray-700 text-zinc-300 font-mono rounded ">
37
- {{ stateLocale.pagIndexCur }}/{{ stateLocale.pagIndexLast }}
38
- </span>
39
- <Config v-if="state.hidden" />
40
- <Close v-if="!state.hidden" />
41
- </span>
42
- </div>
43
-
44
- <Gen :scheme="scheme" :stateLocale="stateLocale" :state="state" v-if="!state.hidden" />
45
- </div>
46
- </template>
47
-
1
+ <script setup lang="ts">
2
+ import Config from './icons/Config.vue';
3
+ import Close from './icons/Close.vue';
4
+ import Gen from './Gen.vue';
5
+ import type { Scheme, UIPosition } from '../types';
6
+ import type { Reactive } from 'vue';
7
+ import type { RecordV } from '../../store/types';
8
+
9
+ const { state, localState, scheme, position } = defineProps<{
10
+ state: Reactive<RecordV>,
11
+ localState: Reactive<RecordV>,
12
+ scheme?: Scheme,
13
+ position: UIPosition
14
+ }>();
15
+
16
+ const optClasses = {
17
+ fixed: 'fixed',
18
+ right: 'right-0',
19
+ left: 'left-0',
20
+ top: 'top-0',
21
+ bottom: 'bottom-0'
22
+ }
23
+
24
+ const pos = Object.entries(position).filter(([_, v]) => v)
25
+ .map(([k, _]) => optClasses[k]).join(' ');
26
+
27
+ </script>
28
+ <template>
29
+ <div class="z-9999 rounded bg-zinc-800 max-w-full p-2 m-2"
30
+ :class="`${state.hidden ? 'hover:bg-gray-600' : ''} ${pos}`" v-if="state.uiEnabled">
31
+
32
+ <div class="flex items-center cursor-pointer py-1 px-2 m-1 rounded"
33
+ :class="!state.hidden ? 'hover:bg-zinc-900' : ''" @click="state.hidden = !state.hidden">
34
+ <span class="m-auto flex mono">
35
+ <span v-if="state.hidden && localState.pagIndexLast as number > 1"
36
+ class="px-3 py-2 mr-2 bg-gray-700 text-zinc-300 font-mono rounded">
37
+ {{ localState.pagIndexCur }}/{{ localState.pagIndexLast }}
38
+ </span>
39
+ <Config v-if="state.hidden" />
40
+ <Close v-if="!state.hidden" />
41
+ </span>
42
+ </div>
43
+
44
+ <Gen :scheme="scheme" :localState="localState" :state="state" v-if="!state.hidden" />
45
+ </div>
46
+ </template>
47
+
48
48
  <style scoped></style>
@@ -1,21 +1,21 @@
1
- <script setup lang="ts">
2
- import type { Reactive } from "vue";
3
- import type { RecordV } from "../../store/types";
4
- import type { Scheme } from "../types";
5
- import RowElement from './RowElement.vue'
6
-
7
- const { scheme, state, stateLocale } = defineProps<{
8
- state: Reactive<RecordV>,
9
- stateLocale: Reactive<RecordV>,
10
- scheme?: Scheme
11
- }>()
12
-
13
- const rows = Object.values(scheme as Scheme);
14
-
15
- </script>
16
-
17
- <template>
18
- <div v-for="row in rows" class="flex items-center bg-zinc-900 py-2 px-2 m-1 font-mono rounded">
19
- <RowElement v-for="r in row" :element="r" :stateLocale="stateLocale" :state="state" />
20
- </div>
1
+ <script setup lang="ts">
2
+ import type { Reactive } from "vue";
3
+ import type { RecordV } from "../../store/types";
4
+ import type { Scheme } from "../types";
5
+ import RowElement from './RowElement.vue'
6
+
7
+ const { scheme, state, localState } = defineProps<{
8
+ state: Reactive<RecordV>,
9
+ localState: Reactive<RecordV>,
10
+ scheme?: Scheme
11
+ }>()
12
+
13
+ const rows = Object.values(scheme as Scheme);
14
+
15
+ </script>
16
+
17
+ <template>
18
+ <div v-for="row in rows" class="flex items-center bg-zinc-900 py-2 px-2 m-1 font-mono rounded">
19
+ <RowElement v-for="r in row" :element="r" :localState="localState" :state="state" />
20
+ </div>
21
21
  </template>
@@ -1,65 +1,66 @@
1
- <script setup lang="ts">
2
- import { computed, type Reactive } from "vue";
3
- import type { RecordV } from "../../store/types";
4
- import type { SchemeRowEl } from "../types";
5
-
6
- const props = defineProps<{
7
- element?: SchemeRowEl,
8
- state: Reactive<RecordV>,
9
- stateLocale: Reactive<RecordV>,
10
- }>();
11
-
12
- const { element, state, stateLocale } = props;
13
-
14
- const { type, model, innerText, label, labelBefore, callback, ...rest } = element as SchemeRowEl;
15
-
16
- const isInput = /checkbox|text|number/.test(type);
17
- const tag = isInput ? 'input' : type;
18
- const ctype = isInput ? type : "";
19
- const id = isInput ? model : (Math.random() * 10000000 | 0).toString(16);
20
-
21
- const componentStyles = {
22
- text: "w-full h-8 text-zinc-300 px-3 py-2 mx-2 rounded-sm bg-zinc-700 outline-none focus:outline-gray-600 hover:bg-zinc-600",
23
- checkbox: "mx-2 size-auto invert checked:invert-0 accent-gray-700",
24
- number: "w-24 h-8 text-zinc-300 rounded px-3 py-2 bg-gray-700 hover:bg-gray-600 outline-none focus:outline-gray-600",
25
- button: "mx-2 size-auto text-zinc-300 rounded px-3 py-2 bg-gray-700 hover:bg-gray-600 ml-auto",
26
- span: "text-zinc-300 ml-auto mr-4",
27
- }
28
-
29
- const innerTextValue = computed(() => {
30
- if (!innerText?.includes('return')) return innerText || "";
31
- const f = new Function('state', 'stateLocale', `${innerText}`);
32
- return f(state, stateLocale);
33
- });
34
-
35
- const value = new Function('state', 'stateLocale', `return ${model || ""}`)(state, stateLocale);
36
- const updateValue = ({ target: { checked, value } }) => {
37
- if (!model?.startsWith("state")) return;
38
- const [stateName, stateProp] = model.split('.');
39
- const val = type === 'checkbox' ? checked : value;
40
- props[stateName][stateProp] = val;
41
- };
42
-
43
- const vif = computed(() => {
44
- if (!element?.['v-if']) return true;
45
- const f = new Function('state', 'stateLocale', `${element['v-if']}`);
46
- return f(state, stateLocale);
47
- });
48
-
49
- // button state
50
- // let callbackWrap: () => Promise<void> | undefined;
51
- // if (callback) {
52
- // callbackWrap = async () => {
53
- // callback();
54
- // }
55
- // }
56
-
57
- </script>
58
- <template>
59
- <label v-if="labelBefore" :for="id" class="text-zinc-300 mx-2 font-mono">{{ labelBefore }}</label>
60
- <component v-if="vif" :id="id" :is="tag" :type="ctype" :class="componentStyles[type]" :checked="!!value"
61
- :value="value" v-on:change="updateValue" v-on:input="updateValue" @click="callback" v-bind="rest">
62
- {{ innerTextValue }}
63
- </component>
64
- <label v-if="label" :for="id" class="text-zinc-300 flex font-mono">{{ label }}</label>
1
+ <script setup lang="ts">
2
+ import { computed, type Reactive } from "vue";
3
+ import type { RecordV } from "../../store/types";
4
+ import type { SchemeRowEl } from "../types";
5
+
6
+ const props = defineProps<{
7
+ element?: SchemeRowEl,
8
+ state: Reactive<RecordV>,
9
+ localState: Reactive<RecordV>,
10
+ }>();
11
+
12
+ const { element, state, localState } = props;
13
+
14
+ const { type, model, innerText, label, labelBefore, callback, ...rest } = element as SchemeRowEl;
15
+
16
+ const isInput = /checkbox|text|number/.test(type);
17
+ const tag = isInput ? 'input' : type;
18
+ const ctype = isInput ? type : "";
19
+ const id = isInput ? model : (Math.random() * 10000000 | 0).toString(16);
20
+
21
+ const componentStyles = {
22
+ text: "w-full h-8 text-zinc-300 px-3 py-2 mx-2 rounded-sm bg-zinc-700 outline-none focus:outline-gray-600 hover:bg-zinc-600",
23
+ checkbox: "mx-2 size-auto invert checked:invert-0 accent-gray-700",
24
+ number: "w-24 h-8 text-zinc-300 rounded px-3 py-2 bg-gray-700 hover:bg-gray-600 outline-none focus:outline-gray-600",
25
+ button: "mx-2 size-auto text-zinc-300 rounded px-3 py-2 bg-gray-700 hover:bg-gray-600 ml-auto",
26
+ span: "text-zinc-300 ml-auto mr-4",
27
+ }
28
+
29
+ const innerTextValue = computed(() => {
30
+ if (!innerText?.includes('return')) return innerText || "";
31
+ const f = new Function('state', 'localState', `${innerText}`);
32
+ return f(state, localState);
33
+ });
34
+
35
+ const value = new Function('state', 'localState', `return ${model || ""}`)(state, localState);
36
+
37
+ const updateValue = ({ target: { checked, value } }) => {
38
+ if (!(typeof model === 'string') || !/^state|localState/.test(model)) return;
39
+ const [stateName, stateProp] = (model).split('.');
40
+ const val = type === 'checkbox' ? checked : value;
41
+ props[stateName][stateProp] = val;
42
+ };
43
+
44
+ const vif = computed(() => {
45
+ if (!element?.['v-if']) return true;
46
+ const f = new Function('state', 'localState', `${element['v-if']}`);
47
+ return f(state, localState);
48
+ });
49
+
50
+ // button state
51
+ // let callbackWrap: () => Promise<void> | undefined;
52
+ // if (callback) {
53
+ // callbackWrap = async () => {
54
+ // callback();
55
+ // }
56
+ // }
57
+
58
+ </script>
59
+ <template>
60
+ <label v-if="labelBefore" :for="id" class="text-zinc-300 mx-2 font-mono">{{ labelBefore }}</label>
61
+ <component v-if="vif" :id="id" :is="tag" :type="ctype" :class="componentStyles[type]" :checked="!!value"
62
+ :value="value" v-on:change="updateValue" v-on:input="updateValue" @click="callback" v-bind="rest">
63
+ {{ innerTextValue }}
64
+ </component>
65
+ <label v-if="label" :for="id" class="text-zinc-300 flex font-mono">{{ label }}</label>
65
66
  </template>
@@ -1,7 +1,7 @@
1
- <template>
2
- <svg class="h-7 w-7 fill-gray-600 stroke-gray-400" xmlns="http://www.w3.org/2000/svg"
3
- fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
4
- <path stroke-linecap="round" stroke-linejoin="round"
5
- d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
6
- </svg>
1
+ <template>
2
+ <svg class="h-7 w-7 fill-gray-600 stroke-gray-400" xmlns="http://www.w3.org/2000/svg"
3
+ fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
4
+ <path stroke-linecap="round" stroke-linejoin="round"
5
+ d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
6
+ </svg>
7
7
  </template>
@@ -1,7 +1,7 @@
1
- <template>
2
- <svg class="h-7 w-7 fill-gray-600 stroke-gray-400" xmlns="http://www.w3.org/2000/svg"
3
- fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
4
- <path strokeLinecap="round" strokeLinejoin="round"
5
- d="M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437 1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008Z" />
6
- </svg>
1
+ <template>
2
+ <svg class="h-7 w-7 fill-gray-600 stroke-gray-400" xmlns="http://www.w3.org/2000/svg"
3
+ fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
4
+ <path strokeLinecap="round" strokeLinejoin="round"
5
+ d="M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437 1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008Z" />
6
+ </svg>
7
7
  </template>