;
7 | };
8 |
9 | export type FileTreeTypes = {
10 | key: FilePath;
11 | title: FileName;
12 | dir: boolean;
13 | isLeaf?: boolean;
14 | children: FileTreeTypes[];
15 | };
16 |
17 | export const defaultFileTree: FileTreeTypes = {
18 | key: '',
19 | title: '',
20 | dir: true,
21 | children: [],
22 | };
23 |
--------------------------------------------------------------------------------
/packages/@rick-utils/index.ts:
--------------------------------------------------------------------------------
1 | // React
2 | export { memoSVC } from './react/memo';
3 |
4 | // Console
5 | export { Logger } from './console/Logger';
6 | export { signature } from './console/signature';
7 |
8 | // File
9 | export { parseDir } from './files/parseDir';
10 | export { parseFiles } from './files/parseFiles';
11 | export { parseZip } from './files/parseZip';
12 | export { sortFiles } from './files/sortFiles';
13 |
14 | // Editor
15 | export { formatCode } from './editor/formatCode';
16 |
17 | // Json
18 | export { isObjectOrJsonString } from './json/isObjectOrJsonString';
19 | export { prettyJsonString } from './json/prettyJsonString';
20 | export { safeJsonParse } from './json/safeJsonParse';
21 |
22 | // Typescript
23 | export type { MakeKeysOptional } from './typescript/MakeKeysOptional';
24 | export type { MakeKeysRequired } from './typescript/MakeKeysRequired';
25 | export type { RecordMapping } from './typescript/RecordMapping';
26 |
27 | // Browser
28 | export { copyText } from './browser/copyText';
29 |
--------------------------------------------------------------------------------
/packages/@rick-utils/json/isObjectOrJsonString.ts:
--------------------------------------------------------------------------------
1 | import { isObject, isString } from 'lodash-es';
2 |
3 | export function isObjectOrJsonString(value: any) {
4 | if (isObject(value)) {
5 | return true;
6 | }
7 |
8 | if (isString(value)) {
9 | try {
10 | return isObject(JSON.parse(value));
11 | } catch (error) {
12 | console.error(error);
13 | return false;
14 | }
15 | }
16 |
17 | return false;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/@rick-utils/json/object.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from 'vitest';
2 | import { isObjectOrJsonString } from './isObjectOrJsonString';
3 | import { safeJsonParse } from './safeJsonParse';
4 |
5 | test('safeJsonParse()', () => {
6 | const obj = { name: 'rick' };
7 | expect(safeJsonParse(JSON.stringify(obj))).toEqual(obj);
8 | expect(safeJsonParse(undefined)).toEqual({});
9 | expect(safeJsonParse(undefined, '')).toEqual('');
10 | });
11 |
12 | test('isObjectOrJsonString()', () => {
13 | expect(isObjectOrJsonString(1)).toBe(false);
14 | expect(isObjectOrJsonString('1')).toBe(false);
15 | expect(isObjectOrJsonString('{}')).toBe(true);
16 | expect(isObjectOrJsonString(false)).toBe(false);
17 | expect(isObjectOrJsonString(true)).toBe(false);
18 | expect(isObjectOrJsonString(JSON.stringify({ name: 'rick' }))).toBe(true);
19 | });
20 |
--------------------------------------------------------------------------------
/packages/@rick-utils/json/prettyJsonString.ts:
--------------------------------------------------------------------------------
1 | import { safeJsonParse } from './safeJsonParse';
2 |
3 | export function prettyJsonString(value: string | object) {
4 | return JSON.stringify(safeJsonParse(value), null, 2);
5 | }
6 |
--------------------------------------------------------------------------------
/packages/@rick-utils/json/safeJsonParse.ts:
--------------------------------------------------------------------------------
1 | import { isObject } from 'lodash-es';
2 |
3 | export function safeJsonParse(value: any, defaultValue = {}) {
4 | if (isObject(value)) {
5 | return value;
6 | }
7 | try {
8 | return JSON.parse(value);
9 | } catch (error) {
10 | console.error(error);
11 | return defaultValue;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/@rick-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rickzhou/react-utils",
3 | "version": "1.0.0",
4 | "private": false,
5 | "description": "React Utils",
6 | "keywords": [
7 | "React",
8 | "Utils"
9 | ],
10 | "homepage": "https://github.com/rick-chou/one-piece-react#readme",
11 | "author": "rick zhou <944268618@qq.com>",
12 | "contributors": [
13 | "rick zhou <944268618@qq.com>"
14 | ],
15 | "type": "module",
16 | "main": "index.ts",
17 | "scripts": {},
18 | "dependencies": {
19 | "eventemitter3": "^5.0.1",
20 | "jszip": "^3.10.1",
21 | "react-fast-compare": "^3.2.2"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/@rick-utils/react/memo.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | ComponentType,
3 | FunctionComponent,
4 | MemoExoticComponent,
5 | NamedExoticComponent,
6 | } from 'react';
7 | import { memo } from 'react';
8 | import isEqual from 'react-fast-compare';
9 |
10 | /**
11 | * @note "SVC" is short for "Shallow-Value-Compare"
12 | */
13 | export function memoSVC>(
14 | Component: FunctionComponent
,
15 | ): NamedExoticComponent
;
16 | export function memoSVC>(
17 | Component: T,
18 | ): MemoExoticComponent {
19 | return memo(Component, isEqual);
20 | }
21 |
--------------------------------------------------------------------------------
/packages/@rick-utils/typescript/MakeKeysOptional.ts:
--------------------------------------------------------------------------------
1 | export type MakeKeysOptional = Partial> &
2 | Omit;
3 |
--------------------------------------------------------------------------------
/packages/@rick-utils/typescript/MakeKeysRequired.ts:
--------------------------------------------------------------------------------
1 | export type MakeKeysRequired = Omit & {
2 | [P in K]-?: T[P];
3 | };
4 |
--------------------------------------------------------------------------------
/packages/@rick-utils/typescript/RecordMapping.ts:
--------------------------------------------------------------------------------
1 | export type RecordMapping = {
2 | [K in keyof T]: T[K];
3 | };
4 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'packages/*'
3 | - 'projects/*'
4 |
--------------------------------------------------------------------------------
/prettier.config.cjs:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @see https://prettier.io/docs/en/configuration.html
5 | * @type {import("prettier").Config}
6 | */
7 | module.exports = {
8 | pluginSearchDirs: false,
9 | plugins: [
10 | require.resolve('prettier-plugin-organize-imports'),
11 | require.resolve('prettier-plugin-packagejson'),
12 | require.resolve('prettier-plugin-tailwindcss'),
13 | ],
14 | tabWidth: 2,
15 | useTabs: false,
16 | singleQuote: true,
17 | semi: true,
18 | bracketSpacing: true,
19 | arrowParens: 'avoid',
20 | trailingComma: 'all',
21 | bracketSameLine: true,
22 | printWidth: 80,
23 | endOfLine: 'lf',
24 | overrides: [
25 | {
26 | files: '*.md',
27 | options: {
28 | proseWrap: 'preserve',
29 | },
30 | },
31 | ],
32 | };
33 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/.env:
--------------------------------------------------------------------------------
1 | RICK_AUTHOR=Rick.Zhou
2 | RICK_GITHUB=https://github.com/rick-chou
3 | RICK_JUEJIN=https://juejin.cn/user/1574156383563496
4 | RICK_ISSUE=https://github.com/rick-chou/one-piece-react/issues/new
5 | RICK_AVATAR=https://cdn.jsdelivr.net/gh/rick-chou/rick-assets/png/2.png
6 |
7 | # CONFIG
8 | RICK_REDUX_LOGGER=false
9 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/.eslintignore:
--------------------------------------------------------------------------------
1 | flipdown.ts
2 | style.ts
3 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/README.md
--------------------------------------------------------------------------------
/projects/@rick-awesome/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 | %RICK_AUTHOR%'s Blog 🚀
18 |
19 |
20 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rickzhou/blog",
3 | "version": "3.0.0",
4 | "private": true,
5 | "description": "Rick.Zhou's Blog 🚀",
6 | "keywords": [
7 | "RICK.ZHOU",
8 | "BLOG",
9 | "FE",
10 | "UI",
11 | "REACT",
12 | "VUE"
13 | ],
14 | "homepage": "https://github.com/rick-chou/react-awesome/",
15 | "author": "Rick.Zhou",
16 | "type": "module",
17 | "scripts": {
18 | "//": "小心使用 不确定大版本是否有breakchange",
19 | "build": "tsc && vite build",
20 | "dev": "vite",
21 | "preview": "tsc && vite build --mode=preview && vite preview --mode=preview",
22 | "update": "npx ncu \\!vue* -u"
23 | },
24 | "dependencies": {
25 | "@emotion/react": "^11.11.1",
26 | "@mdx-js/react": "^2.3.0",
27 | "@mdx-js/rollup": "^2.3.0",
28 | "acorn": "^8.10.0",
29 | "chance": "^1.1.11",
30 | "mdx-mermaid": "^2.0.0",
31 | "mermaid": "^10.5.1",
32 | "mscgenjs": "^6.0.2",
33 | "react-pdf": "^9.2.1",
34 | "react-router-dom": "^6.17.0",
35 | "react-transition-group": "^4.4.5",
36 | "rehype-highlight": "^6.0.0",
37 | "rehype-mdx-code-props": "^1.0.0",
38 | "remark-frontmatter": "^3.0.0",
39 | "remark-gfm": "^3.0.1",
40 | "remark-mdx-frontmatter": "^3.0.0",
41 | "vue2": "npm:vue@^2.7.14",
42 | "vue3": "npm:vue@^3.3.4",
43 | "vueCompiler2": "npm:@vue/compiler-sfc@^2.7.14",
44 | "vueCompiler3": "npm:@vue/compiler-sfc@^3.3.4",
45 | "web-vitals": "^3.5.0"
46 | },
47 | "devDependencies": {
48 | "@types/chance": "^1.1.5",
49 | "@types/dagre": "^0.7.51",
50 | "@types/react-transition-group": "^4.4.8",
51 | "@vitejs/plugin-vue": "^4.4.0",
52 | "@vitejs/plugin-vue2": "^2.2.0"
53 | },
54 | "overrides": {
55 | "@vitejs/plugin-vue2": {
56 | "vue": "^3.3.4"
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/public/favicon.ico
--------------------------------------------------------------------------------
/projects/@rick-awesome/public/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/public/icon-192.png
--------------------------------------------------------------------------------
/projects/@rick-awesome/public/icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/public/icon-512.png
--------------------------------------------------------------------------------
/projects/@rick-awesome/public/icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/public/icon-64.png
--------------------------------------------------------------------------------
/projects/@rick-awesome/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/public/icon.png
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/app/index.tsx:
--------------------------------------------------------------------------------
1 | import Blog from '@rickzhou/awesome/blog/layout';
2 | import CmdModal from '@rickzhou/awesome/components/commands';
3 | import { ThemeProvider } from '@rickzhou/react-ui';
4 | import { App as AppWrapper } from 'antd';
5 | import { ScrollRestoration } from 'react-router-dom';
6 |
7 | export const App = () => {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/app/repl/index.tsx:
--------------------------------------------------------------------------------
1 | const Repl = () => {
2 | return (
3 |
4 |
9 |
10 | );
11 | };
12 |
13 | export default Repl;
14 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/docs/demo.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/docs/demo.docx
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/music/between-worlds.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/music/between-worlds.mp3
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/music/index.ts:
--------------------------------------------------------------------------------
1 | export { default as BetweenWorlds } from './between-worlds.mp3';
2 | export { default as MysteryOfLove } from './mystery-of-love.mp3';
3 | export { default as 在雨中 } from './在雨中.mp3';
4 | export { default as 没有理想的人不伤心 } from './没有理想的人不伤心.mp3';
5 | export { default as 爱在夏天 } from './爱在夏天-盛夏之约.mp3';
6 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/music/mystery-of-love.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/music/mystery-of-love.mp3
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/music/在雨中.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/music/在雨中.mp3
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/music/没有理想的人不伤心.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/music/没有理想的人不伤心.mp3
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/music/爱在夏天-盛夏之约.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/music/爱在夏天-盛夏之约.mp3
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/pdf/http.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/pdf/http.pdf
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/pic/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/pic/bg.jpg
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/pic/cover1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/pic/cover1.jpg
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/pic/cover2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/pic/cover2.jpg
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/pic/cover3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-awesome/src/assets/pic/cover3.jpg
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/assets/pic/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Bg } from './bg.jpg';
2 | export { default as Cover1 } from './cover1.jpg';
3 | export { default as Cover2 } from './cover2.jpg';
4 | export { default as Cover3 } from './cover3.jpg';
5 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/components/codepen/index.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeProvider } from '@rickzhou/react-ui';
2 |
3 | const Codepen: React.FC<{ id: string }> = ({ id }) => {
4 | const { theme } = ThemeProvider.useTheme();
5 | return (
6 |
12 | );
13 | };
14 |
15 | export default Codepen;
16 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/components/codesandbox/index.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeProvider } from '@rickzhou/react-ui';
2 |
3 | const Codesandbox: React.FC<{ id: string }> = ({ id }) => {
4 | const { theme } = ThemeProvider.useTheme();
5 | return (
6 |
12 | );
13 | };
14 |
15 | export default Codesandbox;
16 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/components/sequence-chart/index.tsx:
--------------------------------------------------------------------------------
1 | import { uniqueId } from 'lodash-es';
2 | import { renderMsc } from 'mscgenjs';
3 | import { useEffect, useRef } from 'react';
4 |
5 | const SequenceChart: React.FC<{
6 | msc: string;
7 | onClick: (key: string) => void;
8 | }> = ({ msc, onClick }) => {
9 | const id = useRef(uniqueId('msc_sequence_diagram_'));
10 |
11 | const bindEvents = (event: MouseEvent) => {
12 | event.preventDefault();
13 | const path = event.composedPath();
14 | for (const i in path) {
15 | const link = path[i] as HTMLElement;
16 | if ('getAttribute' in link && link.getAttribute('xlink:title')) {
17 | const key = link.getAttribute('xlink:title');
18 | if (key) {
19 | onClick(key);
20 | }
21 |
22 | break;
23 | }
24 | }
25 | };
26 |
27 | useEffect(() => {
28 | const elementId = id.current;
29 |
30 | if (msc) {
31 | document.getElementById(elementId)!.innerHTML = '';
32 | renderMsc(
33 | msc,
34 | {
35 | additionalTemplate: 'fountainpen',
36 | mirrorEntitiesOnBottom: true,
37 | elementId,
38 | styleAdditions: 'backfround: red',
39 | },
40 | handleRenderMscResult,
41 | );
42 | }
43 |
44 | return () => {
45 | document
46 | .getElementById(elementId)
47 | ?.removeEventListener('click', bindEvents);
48 | };
49 | }, [msc]);
50 |
51 | function handleRenderMscResult(pError: Error, pSuccess: string) {
52 | if (pError) {
53 | console.error(pError);
54 | return;
55 | }
56 |
57 | if (pSuccess) {
58 | document
59 | .getElementById(id.current)
60 | ?.addEventListener('click', bindEvents);
61 | return;
62 | }
63 |
64 | console.log('Wat! Error nor success?');
65 | }
66 |
67 | return ;
68 | };
69 |
70 | export default SequenceChart;
71 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/README.mdx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 |
3 | ONE PIECE
4 |
5 |
6 |
11 |
12 | Abandon all the past and bonds, don't begrudge the tears shed for the dream
13 |
- Luffy.
14 |
15 |
16 |
17 |
18 |
19 |
20 | Blog
21 |
22 | |
23 |
24 | JueJin
25 |
26 |
27 |
28 |
29 |
33 |
37 |
41 |
45 |
49 |
53 |
54 |
55 |
56 |
57 | ## 🌈 Time Machine
58 |
59 | ### 2021
60 |
61 | - [x] Graduation! 🥂 🧱 👷🏿♂️
62 | - [x] Vue2 Developer 😀
63 | - [x] React Developer 😍
64 |
65 | ### 2022
66 |
67 | - [x] React Native Developer 😅
68 |
69 | ### 2023
70 |
71 | - [x] Angular2.0+ Developer 🤔
72 | - [x] React Developer 😅
73 | - [x] Learn Java 😎
74 | - [x] Get married 🥰
75 |
76 | ### 2024
77 |
78 | - [x] Our little one has arrived! 🍼🧑🍼👩🍼
79 |
80 | 
81 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/angular/directive.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Angular Quick Start - Directive
3 | ---
4 |
5 | Directive 用来修饰 DOM 给它添加额外的行为
6 |
7 | > Angular 内置指令 https://angular.cn/guide/built-in-directives
8 |
9 | 例如 开发中常用的 `*ngFor` 就是一个指令 用来遍历渲染 DOM 元素
10 |
11 | 可以参考下面的 Link 我为这些指令都编写了用例
12 |
13 | > https://rick-chou.github.io/angular-tutorial/basic-syntax/directive
14 |
15 | 这里我主要介绍一下如何自定义一个自己的指令
16 |
17 | 举个例子 我们希望鼠标移入/移出的时候 DOM 背景色有切换
18 |
19 | ```html
20 |
21 | Highlight me!
22 |
23 | Highlight me!
24 | ```
25 |
26 | 下面 我们来实现这个例子
27 |
28 | ```ts
29 | import { Directive, ElementRef, HostListener, Input } from '@angular/core';
30 |
31 | // Directive装饰器 可以接收一个对象参数 但是现在我们还不需要
32 | @Directive()
33 | export class HighlightDirective {
34 | // 给这个指定定义一个 highlight 属性
35 | @Input() highlight = 'yellow';
36 |
37 | // 这里的 el 就是被我们的指令直接修饰的那个dom
38 | constructor(private el: ElementRef) {
39 | // 你可以在这里直接操作 dom
40 | }
41 |
42 | // 给这个dom定义一个mouseenter的监听器 后面的名字可以自定定义
43 | @HostListener('mouseenter')
44 | onMouseEnter() {
45 | this.highlight(this.highlight);
46 | }
47 |
48 | // 添加鼠标移出的监听器 绑定对应的事件逻辑
49 | @HostListener('mouseleave')
50 | onMouseLeave() {
51 | this.highlight('');
52 | }
53 |
54 | private highlight(color: string) {
55 | this.el.nativeElement.style.backgroundColor = color;
56 | }
57 | }
58 | ```
59 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/angular/rxjs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Angular Quick Start - Rxjs
3 | ---
4 |
5 | 因为 Angular2.0 是构建在 Rxjs 之上的
6 |
7 | 所以在介绍 Angular 具体用法之前 很有必要先介绍一下 Rxjs 的简单使用
8 |
9 | 下面列出了一些你可以具体学习 Rxjs 的 Reference link
10 |
11 | > https://reactive.how/
12 |
13 | > https://www.learnrxjs.io/
14 |
15 | > https://rxjs.dev/
16 |
17 | Rxjs 的官网介绍了很多概念 例如
18 |
19 | - Observable
20 | - Observer
21 | - Subscription
22 | - Operators
23 | - Subject
24 | - Schedulers
25 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/javascript/debounce-throttle.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: JavaScript - debounce & throttle
3 | ---
4 |
5 | ## 函数防抖
6 |
7 | ```js
8 | /*
9 | 函数防抖:一个频繁触发的函数,在规定时间内,只让函数最后一次触发 例如:
10 |
11 | - 用户输入搜索框 避免每次敲击键盘都发送请求
12 | - 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求
13 | - 调整浏览器窗口大小时,resize 次数过于频繁
14 |
15 | 思路:关键在于清零 例如登录按钮点击一秒后发送登录请求 我们就可以创建一个定时器 每次用户点击的时候都清除这个定时器 让定时器重置
16 | 这样就保证了这一秒内不会因为用户都频繁点击而一直发送请求 代码如下
17 | */
18 |
19 | /**
20 | * 防抖函数
21 | * @param fn 要执行的函数
22 | * @param delay 延迟的时间
23 | */
24 | function debounce(fn, delay) {
25 | var timer = null;
26 | return function () {
27 | clearTimeout(timer);
28 | timer = setTimeout(() => {
29 | fn.call(this);
30 | }, delay);
31 | };
32 | }
33 | ```
34 |
35 | ## 函数节流
36 |
37 | ```js
38 | /*
39 | 函数节流:一个函数执行一次后,只有大于设定的执行周期才会执行第二次
40 | 适用场景:有一个频繁触发的函数,在规定时间内,只让函数触发一次 优化性能 例如
41 |
42 | - scroll时间 每隔1s重新计算位置 而不是一直计算
43 | - 浏览器播放时间 每隔1s重新计算一次播放进度
44 |
45 | 思路:需要两个时间 lastTime 和 nowTime 来计算时间差 由此来判断是否执行事件
46 | 先将lastTime初始化为0 然后获取系统时间 做差判断是否大于delay 如果大于则执行事件并将nowTime赋予lastTime 由此完成节流
47 | */
48 |
49 | /**
50 | * 节流函数
51 | * @param fn 要执行的函数
52 | * @param delay 延迟的时间
53 | */
54 | function throttle(fn, delay) {
55 | var lastTime = 0;
56 | return function () {
57 | var nowTime = Date.now();
58 | if (nowTime - lastTime > delay) {
59 | fn.call(this);
60 | lastTime = nowTime;
61 | }
62 | };
63 | }
64 | ```
65 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/javascript/design-patterns-singleton.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: JavaScript - design-patterns-singleton
3 | ---
4 |
5 | 单例模式的定义是: 保证一个类有且仅有一个实例,并提供一个访问它的全局访问点。
6 |
7 | 思路: 用闭包返回一个实例 对这个实例做条件判断 有就返回 没有就初始化 这样我们在每次 new 的时候就只能得到一个实例
8 |
9 | 例如 全局的蒙层 全局的变量都适合用单例模式来创建 因为我们谁也不希望存在两个蒙层
10 |
11 | ```js
12 | const Singleton = (function () {
13 | let instance = null;
14 |
15 | return function (name, age) {
16 | if (instance) {
17 | return instance;
18 | }
19 |
20 | this.name = name;
21 | this.age = age;
22 |
23 | return (instance = this);
24 | };
25 | })();
26 |
27 | // test
28 | const a = new Singleton('rick', 18);
29 | const b = new Singleton('rick', 18);
30 |
31 | console.log(a === b); // true
32 | console.log(a); // { name: 'rick', age: 18 }
33 | ```
34 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/javascript/file-upload.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: JavaScript - file upload
3 | ---
4 |
5 | ## TODO
6 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/javascript/how-equality-operator-work.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: JavaScript - equality operator
3 | ---
4 |
5 | 首先,== 的定义是:
6 |
7 |
8 |
9 | GetValue 会获取一个子表达式的值(消除掉左值引用),在表达式 [] == ![] 中,[] 的结果就是一个空数组的引用,而 ![] 就有意思了,它会按照 11.4.9 和 9.2 节的要求得到 false。比较的行为在 11.9.3 节里,所以翻到 11.9.3:
10 |
11 |
12 |
13 | 在这段算法里,和 `[] == ![]`匹配的是条件 7,所以会递归地调用 `[] == ToNumber(false)` 进行比较。
14 |
15 | 在 9.3 节中定义了 ToNumber 原语,ToNumber(false) 等于 0,于是比较变为 `[] == 0`。
16 |
17 | 在此处因为 [] 是对象,比较过程走分支 9,依 `ToPrimitive([]) == 0` 比较。
18 |
19 | ToPrimitive 默认是调用 toString 方法的(依 8.2.8),于是 ToPrimitice([]) 等于空字符串。
20 |
21 | 结果,`[] == ![]` 的比较最后落到了 `''==false` 上,
22 |
23 | 按照 11.9.3 中的定义会依分支 5 比较 `ToNumber('')==0` ToNumber('') 依 9.3.1 等于 0,所以结果为 true。
24 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/javascript/prototype.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: JavaScript - prototype
3 | ---
4 |
5 | 在 ES2019 中 对于 prototype 的定义为
6 |
7 | > 给其它对象提供共享属性的对象
8 |
9 | 看完后 突然想到了一句话 Vue 中一切组件继承自 Vue 的原型
10 |
11 | 这也解释了为什么在每个组件中都可以直接使用 Vue 的一些方法 因为这些方法被写在了 Vue 的原型上
12 |
13 | 原型对象被创建时,会自动生成一个 `constructor` 属性,指向创建它的构造函数
14 |
15 | 构造函数的`prototype`指向原型对象
16 |
17 | 实例对象的`__proto__`指向原型对象
18 |
19 | (注)如果在 MDN 上查阅`__proto__`这一属性 你可以看到
20 |
21 | > 已废弃 该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。
22 | >
23 | > 警告: 通过现代浏览器的操作属性的便利性,可以改变一个对象的 \[\[Prototype\]\] 属性, 这种行为在每一个 JavaScript 引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在 obj.**proto** = ... 语句上, 它还会影响到所有继承来自该 \[\[Prototype\]\] 的对象,如果你关心性能,你就不应该在一个对象中修改它的 \[\[Prototype\]\]。相反, 创建一个新的且可以继承 \[\[Prototype\]\] 的对象,推荐使用 Object.create\(\)。
24 | >
25 | > 警告: 当 Object.prototype.**proto** 已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在 ECMAScript 2015 规范中被标准化为传统功能,以确保 Web 浏览器的兼容性。为了更好的支持,建议只使用 Object.getPrototypeOf\(\)。
26 |
27 | 官网说的很明白 如果还不理解 看完下面原型链的作用 你应该就明白了
28 |
29 | 这一部分 看着比较绕 但是理解后 对我们还是很有帮助的 比如原型链的作用
30 |
31 | **原型链的作用:** 原型链如此的重要的原因就在于它决定了 `JavaScript` 中继承的实现方式。
32 |
33 | 当我们访问一个属性时,查找机制如下:
34 |
35 | - 访问对象实例属性,有则返回,没有就通过 `__proto__` 去它的原型对象查找。
36 | - 原型对象上找到即返回,找不到,继续通过原型对象的 `__proto__` 查找。
37 | - 一层一层一直找到 `Object.prototype` ,如果找到目标属性即返回,
38 |
39 | 找不到就返回 `undefined`,不会再往下找,因为在往下找 `__proto__` 就是 `null` 了。
40 |
41 | 所以 如果我们用`Object.prototype`去操作了 Object 的原型对象 那么所有的对象都会受到影响 因为 Object 是对象的顶级父类 所有的对象都继承自它们的顶级父类 Object
42 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/network/http-referer.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Network - http header referer
3 | ---
4 |
5 | ## 背景
6 |
7 | 前段日子 在自学做项目的时候发现 明明在项目中引用了线上存在的图片 但是在自己的项目中却怎么也显示出来
8 |
9 | 查阅资料后发现是这些第三方网站设置了**防盗链**
10 |
11 | ## 破解防盗链
12 |
13 | 先说说防盗链的原理,http 协议中,如果从一个网页跳到另一个网页,http 头字段里面会带个 Referer。
14 |
15 | 这里的 Referer 是由于历史原因导致了拼写错误 后来也就一直沿用。
16 |
17 | 图片服务器通过检测 Referer 是否来自规定域名,来进行防盗链。
18 |
19 | 如果盗用网站是 https 的 protocol,而图片链接是 http 的话,
20 |
21 | 则从 https 向 http 发起的请求会因为安全性的规定,而不带 referer,从而实现防盗链的绕过。
22 |
23 | 官方输出图片的时候,判断了来源(Referer),就是从哪个网站访问这个图片,
24 |
25 | 如果是你的网站去加载这个图片,那么 Referer 就是:你的网站地址;
26 |
27 | 你网站地址,肯定没在官方的白名单内,所以就看不到图片了。
28 |
29 | 因此,若不发送 Referer,也就是没有来源。那么官方那边,就认为是从浏览器直接访问的,所以就能加载正常的图片了。
30 |
31 | ```html
32 |
33 | ```
34 |
35 | 比如在掘金上 查看我的一篇文章中一张图片的 Request Headers 就可以看到 Referer
36 |
37 |
38 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/others/cors.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CORS
3 | ---
4 |
5 | > https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
6 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/others/git-branch-manager.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Git branch manager
3 | ---
4 |
5 | > http://matrixzk.github.io/blog/20141104/git-flow-model/
6 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/others/github-actions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Github actions
3 | ---
4 |
5 | > https://docs.github.com/cn/actions/quickstart
6 |
7 | ```yml
8 | # 当前 workflow 的名称
9 | name: Frontend Weekly
10 |
11 | # 指定 workflow 触发的 event
12 | on:
13 | push:
14 | branches:
15 | - main
16 |
17 | # 一个 workflow 由一个或多个 job 组成
18 | jobs:
19 | # job id: 是 job 的唯一标识
20 | build_and_deploy:
21 | # 在 Github 中显示的 job 名称
22 | name: Build and Deploy
23 | # job 运行的环境配置
24 | runs-on: ubuntu-latest
25 | # 一个 job 由多个 step 组成
26 | steps:
27 | # 当前 step 的名字
28 | - name: Checkout
29 | # checkout action 主要用于向 github 仓库拉取源代码
30 | # https://github.com/actions/checkout
31 | uses: actions/checkout@v2
32 | with:
33 | ref: main
34 | - name: Cache
35 | # cache 在这里主要用于缓存 npm,提升构建速率
36 | # https://github.com/actions/cache
37 | uses: actions/cache@v2
38 | # npm 缓存的路径可查看 https://docs.npmjs.com/cli/cache#cache
39 | # 由于这里 runs-on 是 ubuntu-latest,因此配置 ~/.npm
40 | with:
41 | path: ~/.npm
42 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
43 | restore-keys: |
44 | ${{ runner.os }}-node-
45 | - name: Use Node.js
46 | # 配置 Node 执行环境(当前构建的服务器默认没有 Node 环境,可以通过 Action 安装 Node)
47 | # https://github.com/actions/setup-node
48 | uses: actions/setup-node@v1
49 | with:
50 | node-version: 14
51 | - name: Build
52 | # 安装 Node 之后就可以执行构建脚本
53 | run: |
54 | npm install yarn -g
55 | yarn
56 | yarn build
57 | - name: Deploy
58 | # 将构建产物 commit 到一个分支上,用于发布静态站点资源
59 | # https://github.com/peaceiris/actions-gh-pages
60 | uses: peaceiris/actions-gh-pages@v3
61 | with:
62 | # Github 会在 workflow 中自动生成 GIHUBT_TOKEN,用于认证 workflow 的运行
63 | github_token: ${{ secrets.GITHUB_TOKEN }}
64 | # 静态资源目录设置
65 | publish_dir: ./build
66 | # 默认发布到 gh-pages 分支上,可以指定特定的发布分支(不能选拉取代码的分支)
67 | publish_branch: gh-pages
68 | full_commit_message: ${{ github.event.head_commit.message }}
69 | ```
70 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/others/single-page-app-github-refresh-404.md:
--------------------------------------------------------------------------------
1 | ## 背景
2 |
3 | 单页应用部署在 `Github Pages` 后 刷新 404
4 |
5 | ## 解决
6 |
7 | `Github Pages` 在找不到页面的情况下 会默认去加载 `404.html` 利用这个特性
8 |
9 | 我们可以拷贝一份打包后的 `index.html` 重命名成 `404.html` 即可
10 |
11 | 例如在 `build` 后执行命令 `cp dist/index.html dist/404.html`
12 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/react/mobx.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: React Quick Start - Mobx
3 | ---
4 |
5 | ## TODO 施工中 👷♀️
6 |
7 | > EN https://mobx.js.org/README.html
8 |
9 | > CN https://www.mobxjs.com/
10 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/react/redux-toolkit.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: React Quick Start - Redux Toolkit
3 | ---
4 |
5 | > EN https://redux-toolkit.js.org/
6 |
7 |
8 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/content/react/ssr.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: React Quick Start - SSR
3 | ---
4 |
5 | ## TODO 施工中 👷♀️
6 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/layout/content/index.tsx:
--------------------------------------------------------------------------------
1 | import { routes } from '@rickzhou/awesome/router';
2 | import { useEffect, useRef } from 'react';
3 | import {
4 | matchRoutes,
5 | useLocation,
6 | useNavigation,
7 | useOutlet,
8 | } from 'react-router-dom';
9 | import { CSSTransition, SwitchTransition } from 'react-transition-group';
10 | import { animationDelay, mainContainerStyle } from '../style';
11 |
12 | const Content = () => {
13 | const location = useLocation();
14 | const currentRoute = matchRoutes(routes, location)?.at(-1)?.route;
15 | const ref = useRef(null);
16 | const currentOutlet = useOutlet(currentRoute?.path);
17 | const navigation = useNavigation();
18 |
19 | useEffect(() => {
20 | if (navigation.state === 'idle') {
21 | setTimeout(() => {
22 | ref.current?.scrollTo(0, 0);
23 | }, 300);
24 | }
25 | }, [navigation.state]);
26 |
27 | return (
28 |
29 |
30 |
36 | {() => {currentOutlet}
}
37 |
38 |
39 |
40 | );
41 | };
42 |
43 | export default Content;
44 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/layout/header/index.tsx:
--------------------------------------------------------------------------------
1 | import { GithubOutlined } from '@ant-design/icons';
2 | import { css } from '@emotion/react';
3 | import { Hotkey } from '@rickzhou/awesome/config/shortcut';
4 | import {
5 | OpenTypeConfig,
6 | useModalOpen,
7 | } from '@rickzhou/awesome/store/useModalOpenConfigModel';
8 | import { ThemeSwitch } from '@rickzhou/react-ui';
9 | import { Divider } from 'antd';
10 | import {
11 | headerStyle,
12 | searchBarStyle,
13 | userImgStyle,
14 | userNameStyle,
15 | userStyle,
16 | } from '../style';
17 |
18 | const Header = () => {
19 | const { onShow } = useModalOpen(OpenTypeConfig.CommandOpen);
20 |
21 | return (
22 |
23 |
24 |
30 |
31 |
32 |

33 |
34 |
35 |
{import.meta.env.RICK_AUTHOR}
36 |
37 |
38 |
42 |
43 |
window.open(import.meta.env.RICK_GITHUB)}
46 | />
47 |
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | export default Header;
55 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/layout/homepage.tsx:
--------------------------------------------------------------------------------
1 | import Article from '@rickzhou/awesome/blog/components/article';
2 | import Blog from '@rickzhou/awesome/blog/content/README.mdx';
3 | import README from '../../../README.md';
4 |
5 | const Homepage = () => {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | };
13 |
14 | export default Homepage;
15 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/layout/index.tsx:
--------------------------------------------------------------------------------
1 | import { useShortKey } from '@rickzhou/awesome/hooks/useShortkey';
2 | import { useLocation } from 'react-router-dom';
3 | import Content from './content';
4 | import Header from './header';
5 | import Homepage from './homepage';
6 | import Sidebar from './sidebar';
7 | import { containerStyle } from './style';
8 |
9 | const Blog = () => {
10 | const location = useLocation();
11 |
12 | useShortKey();
13 |
14 | const renderContent = () => {
15 | if (location.pathname === import.meta.env.BASE_URL) {
16 | return (
17 |
18 |
19 |
20 | );
21 | }
22 |
23 | return ;
24 | };
25 |
26 | return (
27 |
28 |
29 |
30 |
31 | {renderContent()}
32 |
33 |
34 | );
35 | };
36 |
37 | export default Blog;
38 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/layout/sidebar/index.tsx:
--------------------------------------------------------------------------------
1 | import { metaData } from '@rickzhou/awesome/router/meta-data';
2 | import { genRandomSvg } from '@rickzhou/awesome/utils';
3 | import { isEmpty, startCase, upperCase } from 'lodash-es';
4 | import { memo } from 'react';
5 | import { Link } from 'react-router-dom';
6 | import {
7 | logoStyle,
8 | sideMenuStyle,
9 | sideTitleStyle,
10 | sideWrapperStyle,
11 | sidebarStyle,
12 | } from '../style';
13 |
14 | const SideBar = () => {
15 | return (
16 |
17 |
18 | @{import.meta.env.RICK_AUTHOR}
19 |
20 | {!isEmpty(metaData) &&
21 | Object.entries(metaData)
22 | .reverse()
23 | .map(([key, value]) => {
24 | return (
25 |
26 |
{upperCase(key)}
27 |
28 | {value.map(i => (
29 |
30 |
33 | {startCase(i.name)}
34 |
35 | ))}
36 |
37 |
38 | );
39 | })}
40 |
41 | );
42 | };
43 |
44 | export default memo(SideBar);
45 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/blog/plugins/inject-import.ts:
--------------------------------------------------------------------------------
1 | import * as acorn from 'acorn';
2 |
3 | const impCodesanbox =
4 | "import Codesandbox from '@rickzhou/awesome/blog/components/codesandbox'";
5 |
6 | const impCodepen =
7 | "import Codepen from '@rickzhou/awesome/blog/components/codepen'";
8 |
9 | export default function retextSentenceSpacing() {
10 | return (tree: any, file: any) => {
11 | tree.children.unshift(
12 | {
13 | type: 'mdxjsEsm',
14 | value: impCodesanbox,
15 | data: {
16 | estree: acorn.parse(impCodesanbox, {
17 | ecmaVersion: 2020,
18 | sourceType: 'module',
19 | }),
20 | },
21 | },
22 | {
23 | type: 'mdxjsEsm',
24 | value: impCodepen,
25 | data: {
26 | estree: acorn.parse(impCodepen, {
27 | ecmaVersion: 2020,
28 | sourceType: 'module',
29 | }),
30 | },
31 | },
32 | );
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/components/background/index.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | const Background = styled.div`
4 | position: fixed;
5 | top: 0;
6 | left: 0;
7 | height: 100vh;
8 | width: 100vw;
9 | `;
10 |
11 | export default Background;
12 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/components/commands/style.ts:
--------------------------------------------------------------------------------
1 | import { css } from '@emotion/react';
2 | import { type CommandItemTypes } from '.';
3 |
4 | export const CommandModalContainer = css({
5 | paddingTop: '1rem',
6 | paddingBottom: '0.5rem',
7 | });
8 |
9 | export const CommandModalInputStyle = css({
10 | backgroundColor: 'transparent',
11 | border: 'none',
12 | outline: 'none',
13 | color: '#e5e5e5',
14 | width: '100%',
15 | fontSize: '16px',
16 | lineHeight: 1,
17 | padding: '16px',
18 | marginLeft: '1rem',
19 | marginRight: '1rem',
20 | });
21 |
22 | export const CommandModalInputDividerWrapperStyle = css({
23 | paddingLeft: '16px',
24 | paddingRight: '16px',
25 | marginBottom: '4px',
26 | });
27 |
28 | export const CommandModalInputDividerStyle = css({
29 | backgroundcolor: '#e5e5e514',
30 | height: '1px',
31 | border: 'none',
32 | });
33 |
34 | export const CommandItemTitleStyle = css({
35 | color: 'rgb(128, 128, 128)',
36 | fontSize: '12px',
37 | fontWeight: 700,
38 | paddingTop: '8px',
39 | paddingBottom: '8px',
40 | userSelect: 'none',
41 | paddingLeft: '16px',
42 | marginLeft: '1rem',
43 | textTransform: 'uppercase',
44 | });
45 |
46 | export const CommandListStyle = css({
47 | height: '24rem',
48 | maxHeight: '24rem',
49 | overflowY: 'scroll',
50 | });
51 |
52 | export const CommandItemStyle = (i?: CommandItemTypes) => {
53 | return css({
54 | color: 'var(--color-primary-text)',
55 | fontSize: '13px',
56 | fontFamily: i?.type === 'font' ? i.title : 'inherit',
57 | height: '36px',
58 | paddingTop: '8px',
59 | paddingBottom: '8px',
60 | userSelect: 'none',
61 | paddingLeft: '24px',
62 | cursor: 'pointer',
63 | marginLeft: '1rem',
64 | marginRight: '1rem',
65 | textTransform: 'uppercase',
66 | '&.hover': {
67 | backgroundColor: 'var(--color-primary-bg-hover)',
68 | borderRadius: '4px',
69 | },
70 | });
71 | };
72 |
73 | export const CommandHotkeyStyle = css({
74 | borderRadius: '4px',
75 | padding: '4px',
76 | lineHeight: 1,
77 | margin: '0px',
78 | height: '20px',
79 | minWidth: '20px',
80 | display: 'flex',
81 | alignItems: 'center',
82 | justifyContent: 'center',
83 | textTransform: 'uppercase',
84 | backgroundColor: '#e5e5e51a',
85 | fontSize: '12px',
86 | color: '#e5e5e5',
87 | userSelect: 'none',
88 | });
89 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/components/error-page/index.tsx:
--------------------------------------------------------------------------------
1 | import { Editor, FuzzyText } from '@rickzhou/react-ui';
2 | import { Space } from 'antd';
3 | import { useRouteError } from 'react-router-dom';
4 |
5 | const ErrorPage = () => {
6 | const error = useRouteError() as Error;
7 | return (
8 |
9 |
10 | 🤖 ERROR
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | export default ErrorPage;
18 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/components/iframe/index.tsx:
--------------------------------------------------------------------------------
1 | import { ContentWrapper } from '@rickzhou/awesome/theme/content-wrapper';
2 | import { type FC } from 'react';
3 |
4 | type IframeProps = {
5 | path: string;
6 | };
7 |
8 | const Iframe: FC = ({ path }) => {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | );
16 | };
17 |
18 | export default Iframe;
19 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/components/vue-component/index.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react';
2 | import Vue from 'vue2';
3 | import { version as vue2Version } from 'vue2/package.json';
4 | import { createApp, type defineComponent } from 'vue3';
5 | import { version as vue3Version } from 'vue3/package.json';
6 |
7 | type VueComponentProps = {
8 | vue: ReturnType;
9 | version?: 2 | 3;
10 | };
11 |
12 | const styles = [
13 | 'color: green',
14 | 'background: yellow',
15 | 'font-size: 30px',
16 | 'border: 1px solid red',
17 | 'text-shadow: 2px 2px black',
18 | 'padding: 10px',
19 | ].join(';');
20 |
21 | const VueComponentWrapper: React.FC = ({
22 | vue,
23 | version = 2,
24 | }) => {
25 | const ref = useRef(null);
26 |
27 | useEffect(() => {
28 | console.log(
29 | `%c Vue Version: ${version === 2 ? vue2Version : vue3Version}`,
30 | styles,
31 | );
32 | if (version === 3) {
33 | createApp(vue).mount(ref.current!);
34 | } else {
35 | new Vue({
36 | render: h => h(vue),
37 | }).$mount(ref.current!);
38 | }
39 | }, [vue, version]);
40 |
41 | return ;
42 | };
43 |
44 | export default VueComponentWrapper;
45 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/config/shortcut.ts:
--------------------------------------------------------------------------------
1 | export const Hotkey = {
2 | Shift: '⇧',
3 | Meta: '⌘',
4 | Ctrl: '⌃',
5 | Alt: '⌥',
6 |
7 | ArrowDown: 'ArrowDown',
8 | ArrowUp: 'ArrowUp',
9 | ArrowLeft: 'ArrowLeft',
10 | ArrowRight: 'ArrowRight',
11 | Enter: 'Enter',
12 |
13 | A: 'A',
14 | B: 'B',
15 | C: 'C',
16 | D: 'D',
17 | E: 'E',
18 | F: 'F',
19 | G: 'G',
20 | H: 'H',
21 | I: 'I',
22 | J: 'J',
23 | K: 'K',
24 | L: 'L',
25 | M: 'M',
26 | N: 'N',
27 | O: 'O',
28 | P: 'P',
29 | Q: 'Q',
30 | R: 'R',
31 | S: 'S',
32 | T: 'T',
33 | U: 'U',
34 | V: 'V',
35 | W: 'W',
36 | X: 'X',
37 | Y: 'Y',
38 | Z: 'Z',
39 | };
40 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/config/web-vitals.ts:
--------------------------------------------------------------------------------
1 | import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB } from 'web-vitals';
2 |
3 | onCLS(console.log);
4 | onFID(console.log);
5 | onLCP(console.log);
6 | onTTFB(console.log);
7 | onFCP(console.log);
8 | onINP(console.log);
9 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/hooks/useShortkey.ts:
--------------------------------------------------------------------------------
1 | import { Hotkey } from '@rickzhou/awesome/config/shortcut';
2 | import {
3 | OpenTypeConfig,
4 | useModalOpen,
5 | } from '@rickzhou/awesome/store/useModalOpenConfigModel';
6 | import { last, toUpper } from 'lodash-es';
7 | import { useEffect } from 'react';
8 |
9 | export const useShortKey = () => {
10 | const { onToggle: onCmdToggle } = useModalOpen(OpenTypeConfig.CommandOpen);
11 |
12 | useEffect(() => {
13 | const shortcuts = {
14 | commandModalV1: {
15 | hotkey: [Hotkey.Meta, Hotkey.S],
16 | fn: onCmdToggle,
17 | },
18 | commandModalV2: {
19 | hotkey: [Hotkey.Meta, Hotkey.F],
20 | fn: onCmdToggle,
21 | },
22 | };
23 |
24 | const bindShortcut = (e: KeyboardEvent) => {
25 | if (
26 | (e.metaKey && toUpper(e.key) === Hotkey.S) ||
27 | (e.metaKey && toUpper(e.key) === Hotkey.F)
28 | ) {
29 | e.preventDefault();
30 | }
31 |
32 | Object.entries(shortcuts).forEach(([_, val]) => {
33 | if (val.hotkey.includes(Hotkey.Meta)) {
34 | if (toUpper(e.key) === toUpper(last(val.hotkey)) && e.metaKey) {
35 | val.fn();
36 | }
37 | }
38 |
39 | if (val.hotkey.includes(Hotkey.Ctrl)) {
40 | if (toUpper(e.key) === toUpper(last(val.hotkey)) && e.ctrlKey) {
41 | val.fn();
42 | }
43 | }
44 | });
45 | };
46 |
47 | window.addEventListener('keydown', bindShortcut);
48 |
49 | return () => {
50 | window.removeEventListener('keydown', bindShortcut);
51 | };
52 | }, [onCmdToggle]);
53 | };
54 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'tailwindcss';
2 | @plugin '@tailwindcss/typography';
3 |
4 | @custom-variant dark (&:where(.dark, .dark *));
5 |
6 | /* Typography plugin */
7 | @utility prose {
8 | :not(pre) > code {
9 | &::before,
10 | &::after {
11 | display: none;
12 | }
13 | color: var(--color-slate-500);
14 | background-color: var(--color-stone-100);
15 | border-radius: 0.25rem;
16 | padding: 0.25rem;
17 | margin-left: 0.25rem;
18 | margin-right: 0.25rem;
19 | @apply no-scrollbar;
20 | }
21 | }
22 |
23 | @utility no-scrollbar {
24 | /* Hide scrollbar for Chrome, Safari and Opera */
25 | &::-webkit-scrollbar {
26 | display: none;
27 | }
28 |
29 | /* Hide scrollbar for IE, Edge and Firefox */
30 | -ms-overflow-style: none; /* IE and Edge */
31 | scrollbar-width: none; /* Firefox */
32 | }
33 |
34 | .react-pdf__Page {
35 | @apply overflow-hidden rounded-lg bg-white shadow-md select-text;
36 | }
37 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/interface/index.ts:
--------------------------------------------------------------------------------
1 | export type ThemeMode = 'light' | 'dark';
2 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/main.tsx:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom/client';
2 | import { RouterProvider } from 'react-router-dom';
3 | import { router } from './router';
4 |
5 | import './resource';
6 |
7 | ReactDOM.createRoot(document.getElementById('root')!).render(
8 | ,
9 | );
10 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/chart/sequence/index.tsx:
--------------------------------------------------------------------------------
1 | import SequenceChart from '@rickzhou/awesome/blog/components/sequence-chart';
2 | import { message } from 'antd';
3 | import { msc } from './msc';
4 |
5 | const Sequence = () => {
6 | return (
7 |
8 | {
11 | await message.info(key);
12 | }}
13 | />
14 |
15 | );
16 | };
17 |
18 | export default Sequence;
19 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/chart/sequence/msc.ts:
--------------------------------------------------------------------------------
1 | export const msc = `
2 | msc {
3 | hscale="1.1",
4 | width=${screen.availWidth * 0.35},
5 | wordwraparcs=true;
6 |
7 | Client [url="Client"],
8 | WebFE [url="WebFE"],
9 | RA [url="RA"],
10 | SA [url="SA"],
11 | VA [url="Client"];
12 |
13 | Client -> WebFE [label="authorizationRequest", url="this is a authorizationRequest"];
14 | WebFE rbox WebFE [label="look up authorization based on nonce"];
15 | WebFE rbox WebFE [label="verify authorization signature"];
16 | WebFE -> RA [label="UpdateAuthorization (Authorization)"];
17 | RA rbox RA [label="add responses to authorization"];
18 | RA -> SA [label="Update(Authorization.ID, Authorization)"];
19 | WebFE -> VA [label="UpdateValidations (Authorization)"];
20 | WebFE -> Client [label="defer (authorizationID)"];
21 | VA -> SA [label="Update (Authorization.ID, Authorization)"];
22 | VA -> RA [label="OnValidationUpdate (Authorization)"];
23 | RA rbox RA [label="check that validation sufficient"];
24 | RA rbox RA [label="finalize authorization"];
25 | RA -> SA [label="Update (Authorization.ID, Authorization)"];
26 | RA -> WebFE [label="OnAuthorizationUpdate(Authorization)"];
27 | Client -> WebFE [label="statusRequest"];
28 | WebFE >> Client [label="error / authorization"];
29 | }
30 | `;
31 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/demo/climate/index.tsx:
--------------------------------------------------------------------------------
1 | import Iframe from '@rickzhou/awesome/components/iframe';
2 |
3 | const ClimateDashboard = () => {
4 | return ;
5 | };
6 |
7 | export default ClimateDashboard;
8 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/demo/lion/index.tsx:
--------------------------------------------------------------------------------
1 | import Iframe from '@rickzhou/awesome/components/iframe';
2 |
3 | const Lion = () => {
4 | return ;
5 | };
6 |
7 | export default Lion;
8 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/demo/navigation/style.ts:
--------------------------------------------------------------------------------
1 | import { css } from '@emotion/react';
2 |
3 | export const ulStyle = css`
4 | position: relative;
5 | transform: rotate(-35deg) skew(20deg, 5deg);
6 | `;
7 |
8 | export const listItemStyle = css`
9 | background: var(--color-secondary-bg);
10 | color: var(--color-primary-text);
11 | text-align: center;
12 | height: 2.5em;
13 | width: 4em;
14 | line-height: 2.5em;
15 | border-bottom: 1px solid var(--color-primary-bg-hover);
16 | position: relative;
17 | display: flex;
18 | justify-content: center;
19 | align-items: center;
20 | text-decoration: none;
21 | transition: all 0.25s linear;
22 |
23 | &:hover {
24 | background: var(--color-active);
25 | color: var(--color-primary-text);
26 | transform: translate(0.9em, -0.9em);
27 | transition: all 0.25s linear;
28 |
29 | &:before,
30 | &:after {
31 | transition: all 0.25s linear;
32 | }
33 |
34 | &:before {
35 | background: var(--color-active);
36 | width: 1em;
37 | top: 0.5em;
38 | left: -1em;
39 | }
40 |
41 | &:after {
42 | background: var(--color-active);
43 | width: 1em;
44 | bottom: -2.5em;
45 | left: 1em;
46 | height: 4em;
47 | }
48 | }
49 |
50 | &:before,
51 | &:after {
52 | content: '';
53 | position: absolute;
54 | transition: all 0.25s linear;
55 | width: 0.5em;
56 | }
57 |
58 | &:after {
59 | height: 4em;
60 | background: var(--color-secondary-bg);
61 | bottom: -2.25em;
62 | left: 1.5em;
63 | transform: rotate(90deg) skew(0, 45deg);
64 | }
65 |
66 | &:before {
67 | height: 2.5em;
68 | background: var(--color-secondary-bg);
69 | top: 0.25em;
70 | left: -0.5em;
71 | transform: skewY(-45deg);
72 | }
73 | `;
74 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/demo/puppy/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @author
3 | * @link https://codepen.io/Ma5a/pen/MWBGbOb
4 | */
5 |
6 | import Iframe from '@rickzhou/awesome/components/iframe';
7 |
8 | const Puppy = () => {
9 | return ;
10 | };
11 |
12 | export default Puppy;
13 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/demo/switch/index.tsx:
--------------------------------------------------------------------------------
1 | import { ThemeSwitch } from '@rickzhou/react-ui';
2 |
3 | export default ThemeSwitch;
4 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/rick/blog/index.tsx:
--------------------------------------------------------------------------------
1 | import Article from '@rickzhou/awesome/blog/components/article';
2 | import Sidebar from '@rickzhou/awesome/blog/content/sidebar.md';
3 | import { css } from '@emotion/react';
4 | import { Link } from 'react-router-dom';
5 |
6 | const Blog = () => {
7 | return (
8 |
9 | (
12 | {props.children}
13 | ),
14 | ul: props => (
15 |
23 | ),
24 | }}
25 | />
26 |
27 | );
28 | };
29 |
30 | export default Blog;
31 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/rick/memorial-day/index.tsx:
--------------------------------------------------------------------------------
1 | import { ContentWrapper } from '@rickzhou/awesome/theme/content-wrapper';
2 | import { ThemeProvider } from '@rickzhou/react-ui';
3 | import dayjs from 'dayjs';
4 | import { memo, useEffect, useRef, useState } from 'react';
5 | import { FlipDown } from './flipdown';
6 | import { flipdownStyle } from './style';
7 |
8 | const getYear = () => {
9 | const now = dayjs();
10 | const currentYear = now.year();
11 | const targetDate = dayjs(`${currentYear}-11-24`);
12 |
13 | if (now.isBefore(targetDate)) {
14 | return currentYear;
15 | } else {
16 | return currentYear + 1;
17 | }
18 | };
19 |
20 | const Countdown = () => {
21 | const instance = useRef();
22 | const { getInverseTheme } = ThemeProvider.useTheme();
23 | const [nextYear] = useState(getYear);
24 |
25 | useEffect(() => {
26 | instance.current = new FlipDown(
27 | Number(new Date(`${nextYear}-11-24`)) / 1000,
28 | ).start();
29 | }, [nextYear]);
30 |
31 | return (
32 |
33 |
34 | The {nextYear - 2023} th anniversary of marriage in
35 |
36 |
41 |
42 | );
43 | };
44 |
45 | export default memo(Countdown);
46 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/rick/music/config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BetweenWorlds,
3 | MysteryOfLove,
4 | 在雨中,
5 | 没有理想的人不伤心,
6 | 爱在夏天,
7 | } from '@rickzhou/awesome/assets/music';
8 | import { Cover1, Cover2, Cover3 } from '@rickzhou/awesome/assets/pic';
9 | import { random } from 'lodash-es';
10 |
11 | const cover = [Cover1, Cover2, Cover3];
12 |
13 | export type TrackType = {
14 | name: string;
15 | artist: string;
16 | cover: string;
17 | source: string;
18 | favorites: boolean;
19 | };
20 |
21 | const getRandomCover = () => {
22 | const id = random(0, 2);
23 | return cover.at(id)!;
24 | };
25 |
26 | export const tracks: TrackType[] = [
27 | {
28 | name: '没有理想的人不伤心',
29 | artist: '新裤子',
30 | cover: getRandomCover(),
31 | source: 没有理想的人不伤心,
32 | favorites: true,
33 | },
34 | {
35 | name: '在雨中',
36 | artist: '韩寒',
37 | cover: getRandomCover(),
38 | source: 在雨中,
39 | favorites: true,
40 | },
41 | {
42 | name: '爱在夏天',
43 | artist: '告五人',
44 | cover: getRandomCover(),
45 | source: 爱在夏天,
46 | favorites: true,
47 | },
48 | {
49 | name: 'Mystery Of Love',
50 | artist: 'Sufjan Stevens',
51 | cover: getRandomCover(),
52 | source: MysteryOfLove,
53 | favorites: true,
54 | },
55 | {
56 | name: 'Between Worlds',
57 | artist: 'Roger Subirana',
58 | cover: getRandomCover(),
59 | source: BetweenWorlds,
60 | favorites: true,
61 | },
62 | ];
63 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/rick/music/index.tsx:
--------------------------------------------------------------------------------
1 | import VueComponentWrapper from '@rickzhou/awesome/components/vue-component';
2 | import Cpn from './index.v2.vue';
3 |
4 | const Music = () => {
5 | return ;
6 | };
7 |
8 | export default Music;
9 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/modules/settings/vscode-config/index.tsx:
--------------------------------------------------------------------------------
1 | import { Editor } from '@rickzhou/react-ui';
2 | import { memoSVC, prettyJsonString } from '@rickzhou/react-utils';
3 | import plugins from '@root/configs/vscode-plugins.txt?raw';
4 | import settings from '@root/configs/vscode-settings.json?raw';
5 | import { Segmented, Space, Tabs } from 'antd';
6 | import { useState } from 'react';
7 | import { contentHeight } from '../../../theme';
8 |
9 | enum Tab {
10 | Settings = 'Settings',
11 | Plugins = 'Plugins',
12 | }
13 |
14 | const VscodeConfig = memoSVC(() => {
15 | const [currentTab, setCurrentTab] = useState(Tab.Settings);
16 | return (
17 |
18 | options={Object.values(Tab)} onChange={setCurrentTab} />
19 | }
22 | items={[
23 | {
24 | label: Tab.Settings,
25 | key: Tab.Settings,
26 | children: (
27 |
33 | ),
34 | },
35 | {
36 | label: Tab.Plugins,
37 | key: Tab.Plugins,
38 | children: (
39 |
45 | ),
46 | },
47 | ]}
48 | />
49 |
50 | );
51 | });
52 |
53 | export default VscodeConfig;
54 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/resource.ts:
--------------------------------------------------------------------------------
1 | // css
2 | import './index.css';
3 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/router/blog.tsx:
--------------------------------------------------------------------------------
1 | const blogs = import.meta.glob(['../blog/content/*/*.{md,mdx}']);
2 |
3 | import Article from '@rickzhou/awesome/blog/components/article';
4 | import { type RouteObject } from 'react-router-dom';
5 |
6 | export const BlogRoutes: RouteObject = {
7 | path: 'rick/blog',
8 | children: Object.entries(blogs).map(([key, value]) => {
9 | return {
10 | path: key.split('../blog/content/').at(-1)!.split('.').at(0)!,
11 | async lazy() {
12 | const { default: Component, frontmatter } =
13 | // eslint-disable-next-line @typescript-eslint/consistent-type-imports
14 | (await value()) as typeof import('@rickzhou/awesome/blog/content/README.mdx');
15 |
16 | return {
17 | Component() {
18 | return (
19 |
20 |
21 | {frontmatter?.title}
22 |
23 |
24 |
25 | );
26 | },
27 | };
28 | },
29 | };
30 | }),
31 | };
32 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/router/index.tsx:
--------------------------------------------------------------------------------
1 | import { App } from '@rickzhou/awesome/app';
2 | import ErrorPage from '@rickzhou/awesome/components/error-page';
3 | import {
4 | createBrowserRouter,
5 | redirect,
6 | type RouteObject,
7 | } from 'react-router-dom';
8 | import { BlogRoutes } from './blog';
9 | import { genRoutes } from './meta-data';
10 |
11 | const RickRoutes: RouteObject = genRoutes('rick');
12 | const DemoRoutes: RouteObject = genRoutes('demo');
13 | const ChartRoutes: RouteObject = genRoutes('chart');
14 | const SettingsRoutes: RouteObject = genRoutes('settings');
15 | // const PreviewRoutes: RouteObject = genRoutes('preview');
16 |
17 | export const routes: RouteObject[] = [
18 | {
19 | path: import.meta.env.BASE_URL,
20 | element: ,
21 | children: [DemoRoutes, RickRoutes, ChartRoutes, BlogRoutes, SettingsRoutes],
22 | errorElement: ,
23 | },
24 | {
25 | path: '*',
26 | loader() {
27 | return redirect(import.meta.env.BASE_URL);
28 | },
29 | },
30 | ];
31 |
32 | export const router = createBrowserRouter(routes);
33 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/router/rick.tsx:
--------------------------------------------------------------------------------
1 | import { type RouteObject } from 'react-router-dom';
2 | import { genRoutes } from './meta-data';
3 |
4 | export const RickRoutes: RouteObject = genRoutes('rick');
5 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/store/useModalOpenConfigModel.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useMemo } from 'react';
2 | import { useShallow } from 'zustand/react/shallow';
3 |
4 | export enum OpenTypeConfig {
5 | MaskOpen = 'mask-open',
6 | CommandOpen = 'command-open',
7 | }
8 |
9 | const initialState: Record = {
10 | [OpenTypeConfig.MaskOpen]: false,
11 | [OpenTypeConfig.CommandOpen]: false,
12 | };
13 |
14 | type PayloadType = {
15 | type: OpenTypeConfig;
16 | open: boolean;
17 | };
18 |
19 | import { create } from 'zustand';
20 | import { immer } from 'zustand/middleware/immer';
21 |
22 | type ModelType = {
23 | onOpenChange: (payload: PayloadType) => void;
24 | } & Record;
25 |
26 | const useModalOpenConfigModel = create()(
27 | immer((set, get) => ({
28 | ...initialState,
29 | onOpenChange(payload: PayloadType) {
30 | set(state => {
31 | state[payload.type] = payload.open;
32 | });
33 | },
34 | })),
35 | );
36 |
37 | export const useModalOpen = (openType: OpenTypeConfig) => {
38 | const { open, onOpenChange } = useModalOpenConfigModel(
39 | useShallow(state => ({
40 | open: state[openType],
41 | onOpenChange: state.onOpenChange,
42 | })),
43 | );
44 |
45 | return {
46 | open: useMemo(() => open, [open]),
47 | onShow: useCallback(() => {
48 | onOpenChange({ type: openType, open: true });
49 | }, [onOpenChange, openType]),
50 | onHidden: useCallback(() => {
51 | onOpenChange({ type: openType, open: false });
52 | }, [onOpenChange, openType]),
53 | onToggle: useCallback(() => {
54 | onOpenChange({ type: openType, open: !open });
55 | }, [onOpenChange, openType, open]),
56 | };
57 | };
58 |
59 | export const useLoading = () => {
60 | const {
61 | open: loading,
62 | onHidden: hideLoading,
63 | onShow: showLoading,
64 | } = useModalOpen(OpenTypeConfig.MaskOpen);
65 | return { loading, showLoading, hideLoading };
66 | };
67 |
68 | export const showLoading = () => {
69 | useModalOpenConfigModel
70 | .getState()
71 | .onOpenChange({ type: OpenTypeConfig.MaskOpen, open: true });
72 | };
73 |
74 | export const hideLoading = () => {
75 | useModalOpenConfigModel
76 | .getState()
77 | .onOpenChange({ type: OpenTypeConfig.MaskOpen, open: false });
78 | };
79 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/theme/content-wrapper.tsx:
--------------------------------------------------------------------------------
1 | import { css } from '@emotion/react';
2 | import { type FC, type PropsWithChildren } from 'react';
3 | import { contentHeight } from '.';
4 |
5 | export const ContentWrapper: FC = ({ children }) => {
6 | return (
7 |
16 | {children}
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/theme/index.tsx:
--------------------------------------------------------------------------------
1 | export const contentHeight = '65vh';
2 |
3 | export const fonts = [
4 | 'Edu AU VIC WA NT Guides',
5 | 'Fira Code',
6 | 'Odibee Sans',
7 | 'Oswald',
8 | 'Teko',
9 | 'Roboto',
10 | ].sort();
11 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/type.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'flipdown';
2 |
3 | declare module '*.js';
4 | declare module '*.cjs';
5 | declare module '*.mjs';
6 |
7 | declare module '*.vue' {
8 | import { type defineComponent } from 'vue';
9 | const Component: ReturnType;
10 | export default Component;
11 | }
12 |
13 | declare module '*.mdx' {
14 | export const frontmatter: { title: string };
15 | }
16 |
17 | // Support markdown extensions from
18 | // https://github.com/sindresorhus/markdown-extensions/blob/v1.1.1/markdown-extensions.json
19 |
20 | /**
21 | * A markdown file which exports a JSX component.
22 | */
23 | declare module '*.md' {
24 | export { default, frontmatter } from '*.mdx';
25 | }
26 |
--------------------------------------------------------------------------------
/projects/@rick-awesome/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | interface ImportMetaEnv {
4 | readonly RICK_AUTHOR: string;
5 | readonly RICK_GITHUB: string;
6 | readonly RICK_JUEJIN: string;
7 | readonly RICK_ISSUE: string;
8 | readonly RICK_AVATAR: string;
9 |
10 | readonly RICK_REDUX_LOGGER: 'true' | 'false';
11 | }
12 |
13 | interface ImportMeta {
14 | readonly env: ImportMetaEnv;
15 | }
16 |
--------------------------------------------------------------------------------
/projects/@rick-repl/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: DEPLOY
2 | on:
3 | push:
4 | branches:
5 | - main
6 |
7 | jobs:
8 | Deploy:
9 | runs-on: ubuntu-latest
10 | needs: Build
11 | steps:
12 | - name: Deploy 🚀
13 | # https://github.com/peaceiris/actions-gh-pages
14 | uses: peaceiris/actions-gh-pages@v3
15 | with:
16 | personal_token: ${{ secrets.ACCESS_TOKEN }}
17 | publish_dir: .
18 | publish_branch: gh-pages
19 | keep_files: true
20 | full_commit_message: ${{ github.event.head_commit.message }}
21 | user_name: 'github-actions[bot]'
22 | user_email: 'github-actions[bot]@users.rick-chou.github.com'
23 |
--------------------------------------------------------------------------------
/projects/@rick-repl/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 | @RickZhou/Playground
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/projects/@rick-repl/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rickzhou/react-repl",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "React Playground",
6 | "type": "module",
7 | "scripts": {
8 | "build": "tsc && vite build",
9 | "dev": "vite"
10 | },
11 | "dependencies": {
12 | "@babel/standalone": "^7.26.2",
13 | "@dnd-kit/core": "^6.2.0",
14 | "@dnd-kit/sortable": "^9.0.0",
15 | "@dnd-kit/utilities": "^3.2.2",
16 | "monaco-editor": "^0.40.0",
17 | "monaco-editor-textmate": "^4.0.0",
18 | "monaco-tailwindcss": "^0.6.1",
19 | "monaco-textmate": "^3.0.1",
20 | "onigasm": "^2.2.5"
21 | },
22 | "devDependencies": {
23 | "@types/babel__standalone": "^7.1.9",
24 | "@types/eslint": "^9.6.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/projects/@rick-repl/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/public/favicon.ico
--------------------------------------------------------------------------------
/projects/@rick-repl/public/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/public/icon-192.png
--------------------------------------------------------------------------------
/projects/@rick-repl/public/icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/public/icon-512.png
--------------------------------------------------------------------------------
/projects/@rick-repl/public/icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/public/icon-64.png
--------------------------------------------------------------------------------
/projects/@rick-repl/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/public/icon.png
--------------------------------------------------------------------------------
/projects/@rick-repl/src/Repl.tsx:
--------------------------------------------------------------------------------
1 | import '@rickzhou/react-repl/setup/index';
2 | import { App, Spin, Splitter } from 'antd';
3 | import { SideInitWidth } from './config/const';
4 | import Editor from './editor';
5 | import { useInit } from './hooks/useInit';
6 | import Preview from './preview';
7 |
8 | const Repl = () => {
9 | const { loading, compiler, formatter, linter } = useInit();
10 |
11 | if (loading) {
12 | return (
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | };
33 |
34 | export default Repl;
35 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/github.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/src/assets/webp/github.webp
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/index.ts:
--------------------------------------------------------------------------------
1 | export { default as github } from './github.webp';
2 | export { default as js } from './js.webp';
3 | export { default as react } from './react.webp';
4 | export { default as vscode } from './vscode.webp';
5 |
6 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/js.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/src/assets/webp/js.webp
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/python.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/src/assets/webp/python.webp
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/react.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/src/assets/webp/react.webp
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/vscode.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/src/assets/webp/vscode.webp
--------------------------------------------------------------------------------
/projects/@rick-repl/src/assets/webp/vue.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rick-chou/one-piece-react/1443e84616e926f49656946e0cd4090e29cd6f7c/projects/@rick-repl/src/assets/webp/vue.webp
--------------------------------------------------------------------------------
/projects/@rick-repl/src/config/const.ts:
--------------------------------------------------------------------------------
1 | export const TabHeight = 32;
2 |
3 | export const SideMinWidth = 0;
4 | export const SideMaxWidth = '100%';
5 | export const SideInitWidth = '50%';
6 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/hooks/useTabs.ts:
--------------------------------------------------------------------------------
1 | import { defaultTabs } from '@rickzhou/react-repl/setup/defaultTabs';
2 | import { type Tab } from '@rickzhou/react-repl/types';
3 | import { useLocalStorageState } from 'ahooks';
4 | import { Uri, editor } from 'monaco-editor';
5 |
6 | export const useTabs = () => {
7 | const [tabs, setTabs] = useLocalStorageState('tab', {
8 | defaultValue: defaultTabs,
9 | });
10 |
11 | const setTabsWrapper = (_tabs: Tab[]) => {
12 | setTabs(_tabs);
13 | };
14 |
15 | const updateTab = (path: string, action: 'add' | 'remove' | 'rename', newPath?: string) => {
16 | const _tabs = [...(tabs || [])];
17 |
18 | switch (action) {
19 | case 'add': {
20 | _tabs.push({ path, content: '' });
21 | editor.createModel('', undefined, Uri.parse(path));
22 | break;
23 | }
24 |
25 | case 'remove': {
26 | const idx = _tabs.findIndex(i => i.path === path);
27 | editor.getModel(Uri.parse(_tabs[idx].path))?.dispose();
28 | _tabs.splice(idx, 1);
29 | break;
30 | }
31 |
32 | case 'rename': {
33 | const idx = _tabs.findIndex(i => i.path === path);
34 | _tabs.splice(idx, 1, {
35 | path: newPath!,
36 | content: editor.getModel(Uri.parse(path))!.getValue(),
37 | });
38 | break;
39 | }
40 |
41 | default:
42 | }
43 |
44 | setTabs(_tabs);
45 | };
46 |
47 | return {
48 | tabs: tabs!,
49 | setTabs: setTabsWrapper,
50 | updateTab,
51 | };
52 | };
53 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/hooks/useTheme.ts:
--------------------------------------------------------------------------------
1 | import { useLocalStorageState, useMount } from 'ahooks';
2 |
3 | import vsDark from '@rickzhou/react-repl/setup/vs_dark_rick.json';
4 | import vsLight from '@rickzhou/react-repl/setup/vs_light_rick.json';
5 | import { editor } from 'monaco-editor';
6 |
7 | export const useTheme = () => {
8 | useMount(() => {
9 | // monaco's built-in themes aren't powerful enough to handle TM tokens
10 | // https://github.com/Nishkalkashyap/monaco-vscode-textmate-theme-converter#monaco-vscode-textmate-theme-converter
11 | editor.defineTheme('vs-dark-rick', vsDark as editor.IStandaloneThemeData);
12 | editor.defineTheme('vs-light-rick', vsLight as editor.IStandaloneThemeData);
13 | });
14 |
15 | const [theme, setTheme] = useLocalStorageState('theme', {
16 | defaultValue: 'vs-light-rick',
17 | });
18 |
19 | return {
20 | theme,
21 | setTheme,
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | overscroll-behavior: none;
4 | font-family: Avenir, Helvetica, Arial, sans-serif !important;
5 | }
6 |
7 | svg {
8 | vertical-align: inherit;
9 | }
10 |
11 | .ant-tabs-editable > .ant-tabs-nav .ant-tabs-tab {
12 | transition: none;
13 | border-radius: 0px !important;
14 | }
15 |
16 | .ant-tabs-nav-add {
17 | border-radius: 0px !important;
18 | }
19 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/main.tsx:
--------------------------------------------------------------------------------
1 | import Repl from '@rickzhou/react-repl/Repl';
2 | import ReactDOM from 'react-dom/client';
3 |
4 | import '@rickzhou/react-ui/tailwind.css';
5 | import './index.css';
6 |
7 | ReactDOM.createRoot(document.getElementById('root')!).render();
8 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/preview/index.tsx:
--------------------------------------------------------------------------------
1 | import { type ReplProps } from '@rickzhou/react-repl/types';
2 | import { useRef } from 'react';
3 | import iframe from './iframe.html?raw';
4 |
5 | const url = URL.createObjectURL(new Blob([iframe], { type: 'text/html' }));
6 |
7 | const Preview: React.FC = ({ compiler }) => {
8 | const iframeRef = useRef(null);
9 |
10 | compiler?.addEventListener('message', ({ data }) => {
11 | if (data.type === 'UPDATE_CODE') {
12 | iframeRef.current?.contentWindow?.postMessage(data);
13 | }
14 | });
15 |
16 | return (
17 |
24 | );
25 | };
26 |
27 | export default Preview;
28 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/setup/default/app.tsx:
--------------------------------------------------------------------------------
1 | import { key, repo } from './const';
2 |
3 | const GithubOutlined = () => {
4 | return (
5 |
14 | );
15 | };
16 |
17 | const RickPlayGround = () => {
18 | return (
19 |
25 | );
26 | };
27 |
28 | export default RickPlayGround;
29 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/setup/default/const.tsx:
--------------------------------------------------------------------------------
1 | export const key = `@RickZhou/Playground`;
2 | export const repo = `https://github.com/rick-chou/one-piece-react/tree/main/projects/@rick-repl`;
3 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/setup/default/main.tsx:
--------------------------------------------------------------------------------
1 | import { createRoot } from 'react-dom/client';
2 | import App from './app';
3 | import './style.css';
4 |
5 | createRoot(document.getElementById('root')!).render();
6 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/setup/default/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | height: 100vh;
6 | width: 100vw;
7 | }
8 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/setup/defaultTabs.ts:
--------------------------------------------------------------------------------
1 | import { type Tab } from '@rickzhou/react-repl/types';
2 | import { last } from 'lodash-es';
3 |
4 | const defaultContent: Record = import.meta.glob('./default/*', {
5 | eager: true,
6 | query: 'raw',
7 | import: 'default',
8 | });
9 |
10 | const defaultTabs: Tab[] = Object.entries(defaultContent).map(([path, content]) => {
11 | return {
12 | path: `file:///${last(path.split('/'))!}`,
13 | content,
14 | };
15 | });
16 |
17 | export { defaultTabs };
18 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/setup/index.ts:
--------------------------------------------------------------------------------
1 | import { languages } from 'monaco-editor';
2 | import { wireTmGrammars } from 'monaco-editor-textmate';
3 | import { Registry } from 'monaco-textmate';
4 | import { loadWASM } from 'onigasm';
5 | import onigasm from 'onigasm/lib/onigasm.wasm?url';
6 | import typescriptReactTM from './TypeScriptReact.tmLanguage.json';
7 | import cssTM from './css.tmLanguage.json';
8 |
9 | let loadingWasm: Promise;
10 |
11 | const registry = new Registry({
12 | async getGrammarDefinition(scopeName) {
13 | return {
14 | format: 'json',
15 | content: scopeName === 'source.tsx' ? typescriptReactTM : cssTM,
16 | };
17 | },
18 | });
19 |
20 | const grammars = new Map();
21 | grammars.set('typescript', 'source.tsx');
22 | grammars.set('javascript', 'source.tsx');
23 | grammars.set('css', 'source.css');
24 |
25 | const hookLanguages = languages.setLanguageConfiguration;
26 |
27 | languages.setLanguageConfiguration = (languageId: string, configuration: languages.LanguageConfiguration) => {
28 | liftOff();
29 | return hookLanguages(languageId, configuration);
30 | };
31 |
32 | export async function liftOff(): Promise {
33 | if (!loadingWasm) {
34 | loadingWasm = loadWASM(onigasm);
35 | await loadingWasm;
36 | }
37 |
38 | // wireTmGrammars only cares about the language part, but asks for all of monaco
39 | // we fool it by just passing in an object with languages
40 | await wireTmGrammars({ languages } as any, registry, grammars);
41 | }
42 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/types/index.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Context
3 | * -------------------------------------------
4 | */
5 |
6 | export type Tab = {
7 | path: string;
8 | content: string;
9 | };
10 |
11 | export type ReplProps = {
12 | compiler?: Worker;
13 | formatter?: Worker;
14 | linter?: Worker;
15 | };
16 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | interface Window {
4 | Monaco: any;
5 | }
6 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/worker/formatter.worker.ts:
--------------------------------------------------------------------------------
1 | import { default as prettierConfig } from '@root/prettier.config.cjs';
2 | import { type Config } from 'prettier';
3 | import pluginsBabel from 'prettier/plugins/babel';
4 | import pluginEstree from 'prettier/plugins/estree';
5 | import prettier from 'prettier/standalone';
6 |
7 | async function format(code: string) {
8 | return prettier.format(code, {
9 | ...(prettierConfig as Config),
10 | parser: 'babel-ts',
11 | plugins: [pluginsBabel, pluginEstree],
12 | });
13 | }
14 |
15 | self.addEventListener('message', async ({ data }) => {
16 | const { event, code } = data;
17 |
18 | switch (event) {
19 | case 'FORMAT':
20 | self.postMessage({
21 | event: 'FORMAT',
22 | code: await format(code),
23 | });
24 | break;
25 | default:
26 | break;
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/worker/linter.worker.ts:
--------------------------------------------------------------------------------
1 | // TODO
2 |
--------------------------------------------------------------------------------
/projects/@rick-repl/src/worker/tailwindcss.worker.ts:
--------------------------------------------------------------------------------
1 | import 'monaco-tailwindcss/tailwindcss.worker';
2 |
--------------------------------------------------------------------------------
/scripts/export-vscode-configs.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs/promises';
2 | import { spawn } from 'node:child_process';
3 | import path from 'node:path';
4 | import os from 'os';
5 | import { __dirname } from './polyfills';
6 |
7 | async function exportVscodePlugins() {
8 | const exportProcess = spawn('code-insiders', ['--list-extensions']);
9 | let plugins = '';
10 | exportProcess.stdout.on('data', data => {
11 | plugins += data.toString();
12 | });
13 |
14 | exportProcess.on('close', async () => {
15 | fs.writeFile(
16 | path.resolve(__dirname, '../configs/vscode-plugins.txt'),
17 | plugins,
18 | 'utf-8',
19 | );
20 | });
21 | }
22 |
23 | async function exportVscodeSettings() {
24 | const settingsPath = path.join(
25 | os.homedir(),
26 | 'Library',
27 | 'Application Support',
28 | 'Code - Insiders',
29 | 'User',
30 | 'settings.json',
31 | );
32 | const config = await fs.readFile(settingsPath, { encoding: 'utf-8' });
33 | fs.writeFile(
34 | path.resolve(__dirname, '../configs/vscode-settings.json'),
35 | config,
36 | 'utf-8',
37 | );
38 | }
39 |
40 | exportVscodePlugins();
41 | exportVscodeSettings();
42 |
--------------------------------------------------------------------------------
/scripts/polyfills.ts:
--------------------------------------------------------------------------------
1 | import { dirname } from 'path';
2 | import { fileURLToPath } from 'url';
3 |
4 | export const __filename = fileURLToPath(import.meta.url);
5 | export const __dirname = dirname(__filename);
6 |
--------------------------------------------------------------------------------
/scripts/regenerate-dependencies.ts:
--------------------------------------------------------------------------------
1 | import { to } from 'await-to-js';
2 | import chalk from 'chalk';
3 | import fs from 'fs';
4 | import { spawn } from 'node:child_process';
5 | import path from 'node:path';
6 | import ora from 'ora';
7 | import { rimraf } from 'rimraf';
8 |
9 | async function deleteNodeModules(dir: string) {
10 | const nodeModulesPath = path.join(dir, 'node_modules');
11 | const lockFilePath = path.join(dir, 'pnpm-lock.yaml');
12 | if (fs.existsSync(nodeModulesPath)) {
13 | const spinner = ora(`removing : ${nodeModulesPath}`).start();
14 | const [err] = await to(rimraf(nodeModulesPath));
15 | if (err) {
16 | spinner.warn(`remove ${nodeModulesPath} ${chalk.bgRedBright('failed')}`);
17 | } else {
18 | spinner.succeed(
19 | `remove ${nodeModulesPath} ${chalk.bgGreenBright('success')}`,
20 | );
21 | }
22 | }
23 |
24 | if (fs.existsSync(lockFilePath)) {
25 | const spinner = ora(`removing : ${lockFilePath}`).start();
26 | const [err] = await to(rimraf(lockFilePath));
27 | if (err) {
28 | spinner.warn(`remove ${lockFilePath} ${chalk.bgRedBright('failed')}`);
29 | } else {
30 | spinner.succeed(
31 | `remove ${lockFilePath} ${chalk.bgGreenBright('success')}`,
32 | );
33 | }
34 | }
35 |
36 | const files = fs.readdirSync(dir);
37 | files.forEach(file => {
38 | const fullPath = path.join(dir, file);
39 | const stat = fs.statSync(fullPath);
40 |
41 | if (stat.isDirectory()) {
42 | deleteNodeModules(fullPath);
43 | }
44 | });
45 | }
46 |
47 | async function installDependencies() {
48 | const pnpmProcess = spawn('pnpm', ['install']);
49 | pnpmProcess.stdout.on('data', data => {
50 | console.log(data.toString());
51 | });
52 | pnpmProcess.stderr.on('data', data => {
53 | console.error(data.toString());
54 | });
55 | }
56 |
57 | const rootDir = process.cwd();
58 | await deleteNodeModules(rootDir);
59 | installDependencies();
60 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4 | "target": "ES2020",
5 | "useDefineForClassFields": true,
6 | "lib": ["ES2020", "ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"],
7 | "module": "ESNext",
8 | "skipLibCheck": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "Bundler",
12 | "allowImportingTsExtensions": true,
13 | "isolatedModules": true,
14 | "moduleDetection": "force",
15 | "noEmit": true,
16 | "jsx": "react-jsx",
17 |
18 | /* Linting */
19 | "strict": true,
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | "noFallthroughCasesInSwitch": true,
23 | "noUncheckedSideEffectImports": true,
24 |
25 | "jsxImportSource": "@emotion/react",
26 |
27 | /* Alias */
28 | "baseUrl": "./",
29 | "paths": {
30 | "@root/*": ["./*"],
31 |
32 | // Projects
33 | "@rickzhou/react-repl/*": ["./projects/@rick-repl/src/*"],
34 | "@rickzhou/react-editor/*": ["./projects/@rick-editor/src/*"],
35 | "@rickzhou/awesome/*": ["./projects/@rick-awesome/src/*"]
36 | }
37 | },
38 | "include": ["packages", "projects", ".github/workflows/App.tsx"],
39 | "exclude": ["roadmap"]
40 | }
41 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4 | "target": "ES2022",
5 | "lib": ["ES2023"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "Bundler",
11 | "allowImportingTsExtensions": true,
12 | "isolatedModules": true,
13 | "moduleDetection": "force",
14 | "noEmit": true,
15 |
16 | /* Linting */
17 | "strict": true,
18 | "noUnusedLocals": true,
19 | "noUnusedParameters": true,
20 | "noFallthroughCasesInSwitch": true,
21 | "noUncheckedSideEffectImports": true
22 | },
23 | "include": ["vite.config.ts"]
24 | }
25 |
--------------------------------------------------------------------------------
/type.def.d.ts:
--------------------------------------------------------------------------------
1 | /* CSS MODULES */
2 | declare module '*.module.css' {
3 | const classes: { [key: string]: string };
4 | export default classes;
5 | }
6 | declare module '*.module.scss' {
7 | const classes: { [key: string]: string };
8 | export default classes;
9 | }
10 | declare module '*.module.sass' {
11 | const classes: { [key: string]: string };
12 | export default classes;
13 | }
14 | declare module '*.module.less' {
15 | const classes: { [key: string]: string };
16 | export default classes;
17 | }
18 | declare module '*.module.styl' {
19 | const classes: { [key: string]: string };
20 | export default classes;
21 | }
22 |
23 | /* CSS */
24 | declare module '*.css';
25 | declare module '*.scss';
26 | declare module '*.sass';
27 | declare module '*.less';
28 | declare module '*.styl';
29 |
30 | /* IMAGES */
31 | declare module '*.svg' {
32 | const ref: string;
33 | export default ref;
34 | }
35 | declare module '*.bmp' {
36 | const ref: string;
37 | export default ref;
38 | }
39 | declare module '*.gif' {
40 | const ref: string;
41 | export default ref;
42 | }
43 | declare module '*.jpg' {
44 | const ref: string;
45 | export default ref;
46 | }
47 | declare module '*.jpeg' {
48 | const ref: string;
49 | export default ref;
50 | }
51 | declare module '*.png' {
52 | const ref: string;
53 | export default ref;
54 | }
55 |
--------------------------------------------------------------------------------