Skip to content

Commit 650e62b

Browse files
committed
Merge branch 'feat/css-xpath-converter' into chore/all-my-stuffs
# Conflicts: # pnpm-lock.yaml # src/tools/index.ts
2 parents 8a18301 + 43ad95d commit 650e62b

File tree

13 files changed

+522
-2
lines changed

13 files changed

+522
-2
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"cron-validator": "^1.3.1",
6666
"cronstrue": "^2.26.0",
6767
"crypto-js": "^4.1.1",
68+
"csstoxpath": "^2.0.0",
6869
"date-fns": "^2.29.3",
6970
"dompurify": "^3.0.6",
7071
"email-bounce-parser-browser": "^1.1",
@@ -116,6 +117,7 @@
116117
"vuedraggable": "^4.1.0",
117118
"xml-formatter": "^3.3.2",
118119
"xml-js": "^1.6.11",
120+
"xpath-to-css": "^1.2.0",
119121
"yaml": "^2.2.1"
120122
},
121123
"devDependencies": {

pnpm-lock.yaml

Lines changed: 18 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
| Selector | Example | Example description |
2+
|-----------------------|-------------------------|----------------------------------------------------------------------------------------------------------|
3+
| `.class` | `.intro` | Selects all elements with class="intro" |
4+
| `.class1.class2` | `.name1.name2` | Selects all elements with both name1 and name2 set within its class attribute |
5+
| `.class1 .class2` | `.name1 .name2` | Selects all elements with name2 that is a descendant of an element with name1 |
6+
| `#id` | `#firstname` | Selects the element with id="firstname" |
7+
| `*` | `*` | Selects all elements |
8+
| `element` | `p` | Selects all \<p\> elements |
9+
| `element.class` | `p.intro` | Selects all \<p\> elements with class="intro" |
10+
| `element,element` | `div, p` | Selects all \<div\> elements and all \<p\> elements |
11+
| `element element` | `div p` | Selects all \<p\> elements inside \<div\> elements |
12+
| `element>element` | `div > p` | Selects all \<p\> elements where the parent is a \<div\> element |
13+
| `element+element` | `div + p` | Selects the first \<p\> element that is placed immediately after \<div\> elements |
14+
| `element1~element2` | `p ~ ul` | Selects every \<ul\> element that is preceded by a \<p\> element |
15+
| `[attribute]` | `[target]` | Selects all elements with a target attribute |
16+
| `[attribute=value]` | `[target="_blank"]` | Selects all elements with target="_blank" |
17+
| `[attribute~=value]` | `[title~="flower"]` | Selects all elements with a title attribute containing the word "flower" |
18+
| `[attribute\|=value]` | `[lang\|="en"]` | Selects all elements with a lang attribute value equal to "en" or starting with "en-" |
19+
| `[attribute^=value]` | `a[href^="https"]` | Selects every \<a\> element whose href attribute value begins with "https" |
20+
| `[attribute$=value]` | `a[href$=".pdf"]` | Selects every \<a\> element whose href attribute value ends with ".pdf" |
21+
| `[attribute*=value]` | `a[href*="w3schools"]` | Selects every \<a\> element whose href attribute value contains the substring "w3schools" |
22+
| `:active` | `a:active` | Selects the active link |
23+
| `::after` | `p::after` | Insert something after the content of each \<p\> element |
24+
| `::before` | `p::before` | Insert something before the content of each \<p\> element |
25+
| `:checked` | `input:checked` | Selects every checked \<input\> element |
26+
| `:default` | `input:default` | Selects the default \<input\> element |
27+
| `:disabled` | `input:disabled` | Selects every disabled \<input\> element |
28+
| `:empty` | `p:empty` | Selects every \<p\> element that has no children (including text nodes) |
29+
| `:enabled` | `input:enabled` | Selects every enabled \<input\> element |
30+
| `:first-child` | `p:first-child` | Selects every \<p\> element that is the first child of its parent |
31+
| `::first-letter` | `p::first-letter` | Selects the first letter of every \<p\> element |
32+
| `::first-line` | `p::first-line` | Selects the first line of every \<p\> element |
33+
| `:first-of-type` | `p:first-of-type` | Selects every \<p\> element that is the first \<p\> element of its parent |
34+
| `:focus` | `input:focus` | Selects the input element which has focus |
35+
| `:fullscreen` | `:fullscreen` | Selects the element that is in full-screen mode |
36+
| `:has()` | `h2:has(+p)` | Selects h2 elements that are immediately followed by a p element, and applies the style to h2 |
37+
| `:hover` | `a:hover` | Selects links on mouse over |
38+
| `:in-range` | `input:in-range` | Selects input elements with a value within a specified range |
39+
| `:indeterminate` | `input:indeterminate` | Selects input elements that are in an indeterminate state |
40+
| `:invalid` | `input:invalid` | Selects all input elements with an invalid value |
41+
| `:lang()` | `p:lang(it)` | Selects every \<p\> element with a lang attribute equal to "it" (Italian) |
42+
| `:last-child` | `p:last-child` | Selects every \<p\> element that is the last child of its parent |
43+
| `:last-of-type` | `p:last-of-type` | Selects every \<p\> element that is the last \<p\> element of its parent |
44+
| `:link` | `a:link` | Selects all unvisited links |
45+
| `::marker` | `::marker` | Selects the markers of list items |
46+
| `:not()` | `:not(p)` | Selects every element that is not a \<p\> element |
47+
| `:nth-child()` | `p:nth-child(2)` | Selects every \<p\> element that is the second child of its parent |
48+
| `:nth-last-child()` | `p:nth-last-child(2)` | Selects every \<p\> element that is the second child of its parent, counting from the last child |
49+
| `:nth-last-of-type()` | `p:nth-last-of-type(2)` | Selects every \<p\> element that is the second \<p\> element of its parent, counting from the last child |
50+
| `:nth-of-type()` | `p:nth-of-type(2)` | Selects every \<p\> element that is the second \<p\> element of its parent |
51+
| `:only-of-type` | `p:only-of-type` | Selects every \<p\> element that is the only \<p\> element of its parent |
52+
| `:only-child` | `p:only-child` | Selects every \<p\> element that is the only child of its parent |
53+
| `:optional` | `input:optional` | Selects input elements with no "required" attribute |
54+
| `:out-of-range` | `input:out-of-range` | Selects input elements with a value outside a specified range |
55+
| `::placeholder` | `input::placeholder` | Selects input elements with the "placeholder" attribute specified |
56+
| `:read-only` | `input:read-only` | Selects input elements with the "readonly" attribute specified |
57+
| `:read-write` | `input:read-write` | Selects input elements with the "readonly" attribute NOT specified |
58+
| `:required` | `input:required` | Selects input elements with the "required" attribute specified |
59+
| `:root` | `:root` | Selects the document's root element |
60+
| `::selection` | `::selection` | Selects the portion of an element that is selected by a user |
61+
| `:target` | `#news:target` | Selects the current active #news element (clicked on a URL containing that anchor name) |
62+
| `:valid` | `input:valid` | Selects all input elements with a valid value |
63+
| `:visited` | `a:visited` | Selects all visited links |
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script setup lang="ts">
2+
import { useThemeVars } from 'naive-ui';
3+
import Memo from './css-selectors-memo.md';
4+
5+
const themeVars = useThemeVars();
6+
</script>
7+
8+
<template>
9+
<div>
10+
<Memo style="overflow-x: auto;" />
11+
</div>
12+
</template>
13+
14+
<style lang="less" scoped>
15+
::v-deep(pre) {
16+
margin: 0;
17+
padding: 15px 22px;
18+
background-color: v-bind('themeVars.cardColor');
19+
border-radius: 4px;
20+
overflow: auto;
21+
}
22+
::v-deep(table) {
23+
border-collapse: collapse;
24+
}
25+
::v-deep(table), ::v-deep(td), ::v-deep(th) {
26+
border: 1px solid v-bind('themeVars.textColor1');
27+
padding: 5px;
28+
}
29+
::v-deep(a) {
30+
color: v-bind('themeVars.textColor1');
31+
}
32+
</style>

src/tools/css-selectors-memo/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { BrandCss3 } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'CSS Selectors Cheatsheet',
6+
path: '/css-selectors-memo',
7+
description: 'CSS Selectors Syntax Cheatsheet',
8+
keywords: ['css', 'selectors', 'cheatsheet', 'memo'],
9+
component: () => import('./css-selectors-memo.vue'),
10+
icon: BrandCss3,
11+
createdAt: new Date('2024-08-15'),
12+
});
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<script setup lang="ts">
2+
import xPathToCss from 'xpath-to-css';
3+
import cssToXpath from 'csstoxpath';
4+
import TextareaCopyable from '@/components/TextareaCopyable.vue';
5+
6+
const cssInput = ref('');
7+
const xpathOutput = computed(
8+
() => {
9+
try {
10+
return cssToXpath(cssInput.value);
11+
}
12+
catch (e: any) {
13+
return e.toString();
14+
}
15+
},
16+
);
17+
18+
const xpathInput = ref('');
19+
const cssOutput = computed(
20+
() => {
21+
try {
22+
return xPathToCss(xpathInput.value);
23+
}
24+
catch (e: any) {
25+
return e.toString();
26+
}
27+
},
28+
);
29+
</script>
30+
31+
<template>
32+
<div max-w-600>
33+
<c-card title="CSS to XPath">
34+
<c-input-text
35+
v-model:value="cssInput"
36+
placeholder="Put your CSS selector here..."
37+
label="CSS selector to convert"
38+
raw-text
39+
mb-5
40+
/>
41+
42+
<router-link target="_blank" to="/css-selectors-memo" mb-1 mt-1>
43+
See CSS Selectors Cheatsheet
44+
</router-link>
45+
46+
<n-divider />
47+
48+
<TextareaCopyable
49+
label="XPath expression"
50+
:value="xpathOutput"
51+
readonly
52+
mb-5
53+
/>
54+
</c-card>
55+
56+
<c-card title="XPath to CSS" mt-5>
57+
<c-input-text
58+
v-model:value="xpathInput"
59+
placeholder="Put your XPath expression here..."
60+
label="XPath expression to convert"
61+
raw-text
62+
mb-5
63+
/>
64+
65+
<router-link target="_blank" to="/xpath-memo" mb-1 mt-1>
66+
See XPath Cheatsheet
67+
</router-link>
68+
69+
<n-divider />
70+
71+
<TextareaCopyable
72+
label="CSS Selector"
73+
:value="cssOutput"
74+
readonly
75+
mb-5
76+
/>
77+
</c-card>
78+
</div>
79+
</template>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "csstoxpath" {
2+
export default function cssToXPath(xpath: string): string;
3+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Braces } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'CSS XPath Converter',
6+
path: '/css-xpath-converter',
7+
description: 'Convert CSS selector to/from XPath expression',
8+
keywords: ['css', 'xpath', 'converter'],
9+
component: () => import('./css-xpath-converter.vue'),
10+
icon: Braces,
11+
createdAt: new Date('2024-08-15'),
12+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "xpath-to-css" {
2+
export default function xpathToCSS(xpath: string): string;
3+
}

src/tools/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import { tool as bounceParser } from './bounce-parser';
66
import { tool as codeHighlighter } from './code-highlighter';
77
import { tool as colorWheel } from './color-wheel';
88

9+
import { tool as cssXpathConverter } from './css-xpath-converter';
10+
import { tool as cssSelectorsMemo } from './css-selectors-memo';
11+
import { tool as xpathMemo } from './xpath-memo';
912
import { tool as asciiTextDrawer } from './ascii-text-drawer';
10-
1113
import { tool as textToUnicode } from './text-to-unicode';
1214
import { tool as certificateKeyParser } from './certificate-key-parser';
1315
import { tool as crcCalculator } from './crc-calculator';
@@ -198,6 +200,9 @@ export const toolsByCategory: ToolCategory[] = [
198200
regexTester,
199201
regexMemo,
200202
commonRegexMemo,
203+
cssXpathConverter,
204+
cssSelectorsMemo,
205+
xpathMemo,
201206
],
202207
},
203208
{

0 commit comments

Comments
 (0)