Skip to content

Commit 29e5895

Browse files
committed
rewrite h -> jsx
1 parent 134f8a1 commit 29e5895

File tree

7 files changed

+68
-95
lines changed

7 files changed

+68
-95
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"scripts": {
66
"format:stylus": "yarn stylus-supremacy format ./source/css/**/*.styl -r --options .supermacy.yml",
7-
"format:pretty": "prettier --write ./{includes,languages,layout,scripts,source,src}/**/*.{pug,js,css,ts}",
7+
"format:pretty": "prettier --write ./{includes,languages,layout,scripts,source,src}/**/*.{pug,js,css,ts,tsx,jsx}",
88
"lint": "yarn eslint . --fix",
99
"format": "yarn format:stylus && yarn format:pretty",
1010
"build": "yarn rollup -c ./rollup.config.mjs"

src/@types/tsx.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module JSX {
2+
type IntrinsicElements = Record<string, any>;
3+
}

src/components/search.ts src/components/search.tsx

+21-19
Original file line numberDiff line numberDiff line change
@@ -124,24 +124,21 @@ export class AnatoloSearch extends Component {
124124
}
125125

126126
makeSearchItem(icon: string | null, title: string | null, slug: string | null, preview: string | null, url: string) {
127-
return h(
128-
'.ins-selectable.ins-search-item',
129-
{
130-
data: { url },
131-
event: {
132-
click: (e) => {
133-
this.gotoLink(url);
134-
},
135-
},
136-
},
137-
[
138-
h('header', [
139-
h(`i.fa.fa-${icon}`),
140-
h('span.ins-title', title != null && title !== '' ? title : this.config.translation['untitled']),
141-
slug ? h('span.ins-slug', slug) : null,
142-
]),
143-
preview ? h('p.ins-search-preview', preview) : null,
144-
],
127+
return (
128+
<div
129+
class="ins-selectable ins-search-item"
130+
data-url={url}
131+
onclick={() => {
132+
this.gotoLink(url);
133+
}}
134+
>
135+
<header>
136+
<i class={`fa fa-${icon}`}></i>
137+
<span class="ins-title">{title != null && title !== '' ? title : this.config.translation['untitled']}</span>
138+
{slug ? <span class="ins-slug">{slug}</span> : null}
139+
</header>
140+
{preview ? <p class="ins-search-preview">{preview}</p> : null}
141+
</div>
145142
);
146143
}
147144

@@ -190,7 +187,12 @@ export class AnatoloSearch extends Component {
190187
return null;
191188
});
192189

193-
return h('section.ins-section', [h('header.ins-section-header', sectionTitle), searchItems]);
190+
return (
191+
<section class="ins-section">
192+
<header class="ins-section-header">{sectionTitle}</header>
193+
{searchItems}
194+
</section>
195+
);
194196
}
195197

196198
async buildFuse() {

src/utils/friend-link.ts

-36
This file was deleted.

src/utils/friend-link.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { escapeHTML, h } from './main';
2+
3+
export function make_friends_list() {
4+
try {
5+
const friendHTML = ({ avatar, href, title, description }: any) => (
6+
<div class="friend-link-container">
7+
<div class="friend-link-box">
8+
<aside class="friend-link-avatar">
9+
<img src={escapeHTML(avatar)} href={escapeHTML(href)} />
10+
</aside>
11+
<div class="friend-link-meta">
12+
<div class="friend-link-title">
13+
<a href={escapeHTML(href)}>{escapeHTML(title)}</a>
14+
</div>
15+
<div class="friend-link-description">{escapeHTML(description)}</div>
16+
</div>
17+
</div>
18+
</div>
19+
);
20+
21+
document.querySelectorAll('.friend-link').forEach((friend) => {
22+
friend.replaceWith(friendHTML((friend as HTMLElement).dataset));
23+
});
24+
} catch (err) {
25+
console.error(err);
26+
}
27+
}

src/utils/html-helper.ts

+13-36
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,23 @@
1-
type Attrs = {
2-
data?: Record<string, string>;
3-
event?: Partial<Record<keyof HTMLElementEventMap, (e: Event) => void>>;
4-
class?: string;
5-
} & Record<string, any>;
1+
type Attrs = Record<string, any> | null;
62

73
type ContentNode = string | HTMLElement | null | undefined;
84

95
type Content = ContentNode | ContentNode[];
106

11-
function h3(ident: string, attrs: Attrs, content?: Content) {
7+
export function h(ident: string, attrs: Attrs, ...content: ContentNode[]) {
128
let [tagName, ...classes] = ident.split('.');
139
if (!tagName) tagName = 'div';
1410
const elem = document.createElement(tagName);
1511
elem.classList.add(...classes);
16-
for (const key of Object.keys(attrs)) {
17-
if (key === 'class' && attrs.class) {
18-
elem.classList.add(...attrs.class.split(' '));
19-
} else if (key === 'data') {
20-
for (const [dataKey, dataVal] of Object.entries(attrs.data || {})) {
21-
elem.dataset[dataKey] = dataVal as string;
12+
if (attrs != null) {
13+
for (const [key, val] of Object.entries(attrs)) {
14+
if (key === 'class' && attrs.class) {
15+
elem.classList.add(...attrs.class.split(' '));
16+
} else if (key.startsWith('on')) {
17+
elem.addEventListener(key.slice(2), val);
18+
} else {
19+
elem.setAttribute(key, val);
2220
}
23-
} else if (key === 'event') {
24-
for (const [eventName, fn] of Object.entries(attrs.event || {})) {
25-
elem.addEventListener(eventName, fn);
26-
}
27-
} else {
28-
elem.setAttribute(key, attrs[key]);
2921
}
3022
}
3123

@@ -37,24 +29,9 @@ function h3(ident: string, attrs: Attrs, content?: Content) {
3729
}
3830
}
3931

40-
if (Array.isArray(content)) {
41-
content.flat().forEach((c) => {
42-
addContent(c);
43-
});
44-
} else {
45-
addContent(content);
46-
}
32+
content.flat().forEach((c) => {
33+
addContent(c);
34+
});
4735

4836
return elem;
4937
}
50-
51-
export function h(ident: string, content?: Content): HTMLElement;
52-
export function h(ident: string, attrs: Attrs, content?: Content): HTMLElement;
53-
54-
export function h(ident: string, attrs_or_content?: Attrs | Content, content?: Content) {
55-
if (Array.isArray(attrs_or_content) || typeof attrs_or_content === 'string' || attrs_or_content == null) {
56-
return h3(ident, {}, attrs_or_content);
57-
} else {
58-
return h3(ident, attrs_or_content, content);
59-
}
60-
}

tsconfig.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
/* Language and Environment */
1414
"target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
1515
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16-
// "jsx": "preserve", /* Specify what JSX code is generated. */
16+
"jsx": "react", /* Specify what JSX code is generated. */
1717
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
1818
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19-
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
19+
"jsxFactory": "h", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
2020
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
2121
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
2222
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
@@ -36,7 +36,7 @@
3636
// "rootDirs": [
3737
// "./src",
3838
// ], /* Allow multiple folders to be treated as one when resolving modules. */
39-
"typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
39+
"typeRoots": ["./src/@types"], /* Specify multiple folders that act like './node_modules/@types'. */
4040
// "types": ["@types"], /* Specify type package names to be included without being referenced in a source file. */
4141
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
4242
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */

0 commit comments

Comments
 (0)