mirror of
https://github.com/motion-canvas/motion-canvas.git
synced 2026-01-11 06:48:12 -05:00
feat: add markdown logs (#138)
This commit is contained in:
@@ -3,5 +3,6 @@
|
||||
"singleQuote": true,
|
||||
"printWidth": 80,
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "avoid"
|
||||
"arrowParens": "avoid",
|
||||
"proseWrap": "always"
|
||||
}
|
||||
|
||||
209
package-lock.json
generated
209
package-lock.json
generated
@@ -4609,6 +4609,10 @@
|
||||
"resolved": "packages/examples",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@motion-canvas/internal": {
|
||||
"resolved": "packages/internal",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@motion-canvas/player": {
|
||||
"resolved": "packages/player",
|
||||
"link": true
|
||||
@@ -5144,6 +5148,60 @@
|
||||
"vite": ">=2.0.0-beta.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-typescript": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.0.0.tgz",
|
||||
"integrity": "sha512-goPyCWBiimk1iJgSTgsehFD5OOFHiAknrRJjqFCudcW8JtWiBlK284Xnn4flqMqg6YAjVG/EE+3aVzrL5qNSzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^5.0.1",
|
||||
"resolve": "^1.22.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^2.14.0||^3.0.0",
|
||||
"tslib": "*",
|
||||
"typescript": ">=3.7.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
},
|
||||
"tslib": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-typescript/node_modules/@rollup/pluginutils": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
|
||||
"integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-typescript/node_modules/@types/estree": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
|
||||
"integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "4.2.1",
|
||||
"dev": true,
|
||||
@@ -11184,6 +11242,15 @@
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/highlight.js": {
|
||||
"version": "11.7.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
|
||||
"integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/history": {
|
||||
"version": "4.10.1",
|
||||
"license": "MIT",
|
||||
@@ -13671,9 +13738,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz",
|
||||
"integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==",
|
||||
"version": "4.2.12",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
|
||||
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
@@ -19054,6 +19121,23 @@
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/ttypescript": {
|
||||
"version": "1.5.15",
|
||||
"resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.15.tgz",
|
||||
"integrity": "sha512-48ykDNHzFnPMnv4hYX1P8Q84TvCZyL1QlFxeuxsuZ48X2+ameBgPenvmCkHJtoOSxpoWTWi8NcgNrRnVDOmfSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"resolve": ">=1.9.0"
|
||||
},
|
||||
"bin": {
|
||||
"ttsc": "bin/tsc",
|
||||
"ttsserver": "bin/tsserver"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ts-node": ">=8.0.2",
|
||||
"typescript": ">=3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"devOptional": true,
|
||||
@@ -20611,13 +20695,14 @@
|
||||
},
|
||||
"packages/2d": {
|
||||
"name": "@motion-canvas/2d",
|
||||
"version": "12.0.1",
|
||||
"version": "12.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"code-fns": "^0.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -20626,7 +20711,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@motion-canvas/core",
|
||||
"version": "12.0.0",
|
||||
"version": "12.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/chroma-js": "^2.1.4",
|
||||
@@ -20634,6 +20719,8 @@
|
||||
"mix-color": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@types/dom-webcodecs": "^0.1.4",
|
||||
"canvas-5-polyfill": "^0.1.5",
|
||||
"typescript": "^4.7.4",
|
||||
@@ -20646,7 +20733,7 @@
|
||||
},
|
||||
"packages/create": {
|
||||
"name": "@motion-canvas/create",
|
||||
"version": "12.0.1",
|
||||
"version": "12.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prompts": "^2.4.2"
|
||||
@@ -20655,10 +20742,10 @@
|
||||
"create-motion-canvas": "index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/2d": "^12.0.1",
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/ui": "^12.0.0",
|
||||
"@motion-canvas/vite-plugin": "^12.0.0"
|
||||
"@motion-canvas/2d": "^12.1.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@motion-canvas/ui": "^12.1.0",
|
||||
"@motion-canvas/vite-plugin": "^12.1.0"
|
||||
}
|
||||
},
|
||||
"packages/docs": {
|
||||
@@ -20717,12 +20804,21 @@
|
||||
"vite": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"packages/internal": {
|
||||
"name": "@motion-canvas/internal",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"highlight.js": "^11.7.0",
|
||||
"marked": "^4.2.12",
|
||||
"ttypescript": "^1.5.15"
|
||||
}
|
||||
},
|
||||
"packages/player": {
|
||||
"name": "@motion-canvas/player",
|
||||
"version": "12.0.0",
|
||||
"version": "12.1.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"terser": "^5.16.1",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.4"
|
||||
@@ -20747,12 +20843,13 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@motion-canvas/ui",
|
||||
"version": "12.0.0",
|
||||
"version": "12.1.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@preact/preset-vite": "^2.3.0",
|
||||
"clsx": "^1.2.1",
|
||||
"highlight.js": "^11.7.0",
|
||||
"preact": "10.7.3",
|
||||
"source-map-js": "^1.0.2",
|
||||
"typescript": "^4.6.4",
|
||||
@@ -20773,12 +20870,13 @@
|
||||
},
|
||||
"packages/vite-plugin": {
|
||||
"name": "@motion-canvas/vite-plugin",
|
||||
"version": "12.0.0",
|
||||
"version": "12.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-types": "^2.1.35"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"@types/mime-types": "^2.1.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.9"
|
||||
@@ -23901,7 +23999,8 @@
|
||||
"@motion-canvas/2d": {
|
||||
"version": "file:packages/2d",
|
||||
"requires": {
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"code-fns": "^0.7.0",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
@@ -23909,6 +24008,8 @@
|
||||
"@motion-canvas/core": {
|
||||
"version": "file:packages/core",
|
||||
"requires": {
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"@rollup/plugin-typescript": "*",
|
||||
"@types/chroma-js": "^2.1.4",
|
||||
"@types/dom-webcodecs": "^0.1.4",
|
||||
"canvas-5-polyfill": "^0.1.5",
|
||||
@@ -23922,10 +24023,10 @@
|
||||
"@motion-canvas/create": {
|
||||
"version": "file:packages/create",
|
||||
"requires": {
|
||||
"@motion-canvas/2d": "^12.0.1",
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/ui": "^12.0.0",
|
||||
"@motion-canvas/vite-plugin": "^12.0.0",
|
||||
"@motion-canvas/2d": "^12.1.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@motion-canvas/ui": "^12.1.0",
|
||||
"@motion-canvas/vite-plugin": "^12.1.0",
|
||||
"prompts": "^2.4.2"
|
||||
}
|
||||
},
|
||||
@@ -23973,10 +24074,18 @@
|
||||
"vite": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"@motion-canvas/internal": {
|
||||
"version": "file:packages/internal",
|
||||
"requires": {
|
||||
"highlight.js": "^11.7.0",
|
||||
"marked": "^4.2.12",
|
||||
"ttypescript": "^1.5.15"
|
||||
}
|
||||
},
|
||||
"@motion-canvas/player": {
|
||||
"version": "file:packages/player",
|
||||
"requires": {
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"terser": "^5.16.1",
|
||||
"typescript": "^4.6.4",
|
||||
"vite": "^3.0.4"
|
||||
@@ -23995,9 +24104,10 @@
|
||||
"@motion-canvas/ui": {
|
||||
"version": "file:packages/ui",
|
||||
"requires": {
|
||||
"@motion-canvas/core": "^12.0.0",
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@preact/preset-vite": "^2.3.0",
|
||||
"clsx": "*",
|
||||
"clsx": "^1.2.1",
|
||||
"highlight.js": "^11.7.0",
|
||||
"preact": "10.7.3",
|
||||
"source-map-js": "^1.0.2",
|
||||
"typescript": "^4.6.4",
|
||||
@@ -24013,6 +24123,7 @@
|
||||
"@motion-canvas/vite-plugin": {
|
||||
"version": "file:packages/vite-plugin",
|
||||
"requires": {
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"@types/mime-types": "^2.1.1",
|
||||
"mime-types": "^2.1.35",
|
||||
"typescript": "^4.7.4",
|
||||
@@ -24381,6 +24492,35 @@
|
||||
"@rollup/pluginutils": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-typescript": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.0.0.tgz",
|
||||
"integrity": "sha512-goPyCWBiimk1iJgSTgsehFD5OOFHiAknrRJjqFCudcW8JtWiBlK284Xnn4flqMqg6YAjVG/EE+3aVzrL5qNSzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@rollup/pluginutils": "^5.0.1",
|
||||
"resolve": "^1.22.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz",
|
||||
"integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
|
||||
"integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@rollup/pluginutils": {
|
||||
"version": "4.2.1",
|
||||
"dev": true,
|
||||
@@ -28220,6 +28360,12 @@
|
||||
"he": {
|
||||
"version": "1.2.0"
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "11.7.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
|
||||
"integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
|
||||
"dev": true
|
||||
},
|
||||
"history": {
|
||||
"version": "4.10.1",
|
||||
"requires": {
|
||||
@@ -29843,9 +29989,9 @@
|
||||
"version": "1.0.4"
|
||||
},
|
||||
"marked": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz",
|
||||
"integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==",
|
||||
"version": "4.2.12",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
|
||||
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
|
||||
"dev": true
|
||||
},
|
||||
"mdast-squeeze-paragraphs": {
|
||||
@@ -33211,6 +33357,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ttypescript": {
|
||||
"version": "1.5.15",
|
||||
"resolved": "https://registry.npmjs.org/ttypescript/-/ttypescript-1.5.15.tgz",
|
||||
"integrity": "sha512-48ykDNHzFnPMnv4hYX1P8Q84TvCZyL1QlFxeuxsuZ48X2+ameBgPenvmCkHJtoOSxpoWTWi8NcgNrRnVDOmfSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"resolve": ">=1.9.0"
|
||||
}
|
||||
},
|
||||
"type-check": {
|
||||
"version": "0.4.0",
|
||||
"devOptional": true,
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"main": "lib/scenes/index.js",
|
||||
"types": "./lib/scenes/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch": "tsc -w"
|
||||
"build": "ttsc",
|
||||
"watch": "ttsc -w"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com/motion-canvas"
|
||||
@@ -28,6 +28,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
1
packages/2d/src/globals.d.ts
vendored
1
packages/2d/src/globals.d.ts
vendored
@@ -1,2 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/// <reference types="@motion-canvas/core/project" />
|
||||
/// <reference types="@motion-canvas/internal" />
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
"paths": {
|
||||
"@motion-canvas/2d/lib/jsx-runtime": ["jsx-runtime.ts"]
|
||||
},
|
||||
"types": ["node"]
|
||||
"types": ["node"],
|
||||
"plugins": [
|
||||
{
|
||||
"transform": "@motion-canvas/internal/transformers/markdown-literals.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"author": "motion-canvas",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"watch": "tsc -p tsconfig.build.json -w",
|
||||
"build": "ttsc -p tsconfig.build.json",
|
||||
"watch": "ttsc -p tsconfig.build.json -w",
|
||||
"test": "vitest"
|
||||
},
|
||||
"publishConfig": {
|
||||
@@ -31,6 +31,8 @@
|
||||
"mix-color": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@types/dom-webcodecs": "^0.1.4",
|
||||
"canvas-5-polyfill": "^0.1.5",
|
||||
"typescript": "^4.7.4",
|
||||
|
||||
2
packages/core/src/globals.d.ts
vendored
2
packages/core/src/globals.d.ts
vendored
@@ -1,3 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/// <reference types="@motion-canvas/internal" />
|
||||
|
||||
declare type Callback = (...args: any[]) => void;
|
||||
|
||||
6
packages/core/src/utils/__logs__/get-reference-value.md
Normal file
6
packages/core/src/utils/__logs__/get-reference-value.md
Normal file
@@ -0,0 +1,6 @@
|
||||
To retrieve the referenced object, invoke the reference like a function:
|
||||
|
||||
```ts
|
||||
ref.value; // wrong
|
||||
ref(); // correct
|
||||
```
|
||||
7
packages/core/src/utils/__logs__/set-reference-value.md
Normal file
7
packages/core/src/utils/__logs__/set-reference-value.md
Normal file
@@ -0,0 +1,7 @@
|
||||
To set the referenced object, pass it to the reference like you would to a
|
||||
function:
|
||||
|
||||
```ts
|
||||
ref.value = object; // wrong
|
||||
ref(object); // correct
|
||||
```
|
||||
@@ -1,4 +1,6 @@
|
||||
import {deprecate} from './deprecate';
|
||||
import getReferenceValue from './__logs__/get-reference-value.md';
|
||||
import setReferenceValue from './__logs__/set-reference-value.md';
|
||||
|
||||
export interface ReferenceReceiver<T> {
|
||||
(reference: T): void;
|
||||
@@ -27,16 +29,14 @@ export function createRef<T>(): Reference<T> {
|
||||
get: deprecate(
|
||||
() => value,
|
||||
'get Reference.value has been deprecated.',
|
||||
`To retrieve the referenced object, invoke the reference like a function:
|
||||
<pre>ref.value; // wrong\nref(); // correct</pre>`,
|
||||
getReferenceValue,
|
||||
),
|
||||
set: deprecate(
|
||||
newValue => {
|
||||
value = newValue;
|
||||
},
|
||||
'set Reference.value has been deprecated.',
|
||||
`To set the referenced object, pass it to the reference like you would to a function:
|
||||
<pre>ref.value = object; // wrong\nref(object); // correct</pre>`,
|
||||
setReferenceValue,
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ export function useThread(): Thread {
|
||||
if (!thread) {
|
||||
throw new DetailedError(
|
||||
'The thread is not available in the current context.',
|
||||
`<code>useThread()</code> can only be called from within generator functions.
|
||||
// language=markdown
|
||||
`\`useThread()\` can only be called from within generator functions.
|
||||
It's not available during rendering.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
"paths": {
|
||||
"@motion-canvas/core/lib/jsx-runtime": ["jsx-runtime.ts"]
|
||||
},
|
||||
"types": ["node", "dom-webcodecs"]
|
||||
"types": ["node", "dom-webcodecs"],
|
||||
"plugins": [
|
||||
{
|
||||
"transform": "@motion-canvas/internal/transformers/markdown-literals.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import {defineConfig} from 'vitest/config';
|
||||
import markdownLiterals from '@motion-canvas/internal/vite/markdown-literals';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [markdownLiterals()],
|
||||
test: {
|
||||
setupFiles: ['./vitest.setup.ts'],
|
||||
environment: 'jsdom',
|
||||
|
||||
4
packages/internal/index.d.ts
vendored
Normal file
4
packages/internal/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module '*.md' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
10
packages/internal/package.json
Normal file
10
packages/internal/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@motion-canvas/internal",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"highlight.js": "^11.7.0",
|
||||
"marked": "^4.2.12",
|
||||
"ttypescript": "^1.5.15"
|
||||
}
|
||||
}
|
||||
81
packages/internal/transformers/markdown-literals.js
Normal file
81
packages/internal/transformers/markdown-literals.js
Normal file
@@ -0,0 +1,81 @@
|
||||
const ts = require('typescript');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const marked = require('marked');
|
||||
|
||||
marked.setOptions({
|
||||
headerIds: false,
|
||||
highlight(code, lang) {
|
||||
const highlightJs = require('highlight.js');
|
||||
const language = highlightJs.getLanguage(lang) ? lang : 'plaintext';
|
||||
return highlightJs.highlight(code, {language}).value;
|
||||
},
|
||||
});
|
||||
marked.use({
|
||||
renderer: {
|
||||
link(href, title, text) {
|
||||
return `<a href='${href}' target='_blank'>${text}</a>`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const transformerProgram = program => context => sourceFile => {
|
||||
const sourceMap = new Map();
|
||||
const visitor = node => {
|
||||
if (
|
||||
(node.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral ||
|
||||
ts.isStringLiteral(node)) &&
|
||||
node.getFullText().trim().startsWith('// language=markdown')
|
||||
) {
|
||||
return ts.factory.createStringLiteral(marked.parse(node.text));
|
||||
}
|
||||
|
||||
if (
|
||||
ts.isImportDeclaration(node) &&
|
||||
ts.isStringLiteral(node.moduleSpecifier) &&
|
||||
node.importClause.name !== undefined
|
||||
) {
|
||||
/**
|
||||
* @type {ts.TypeChecker}
|
||||
*/
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const moduleSymbol = typeChecker.getSymbolAtLocation(
|
||||
node.moduleSpecifier,
|
||||
);
|
||||
if (moduleSymbol.escapedName !== '"*.md"') {
|
||||
return node;
|
||||
}
|
||||
|
||||
const baseDir = path.dirname(sourceFile.fileName);
|
||||
const content = marked.parse(
|
||||
fs.readFileSync(
|
||||
path.resolve(baseDir, node.moduleSpecifier.text),
|
||||
'utf-8',
|
||||
),
|
||||
);
|
||||
|
||||
const variableSymbol = typeChecker.getSymbolAtLocation(
|
||||
node.importClause.name,
|
||||
);
|
||||
|
||||
sourceMap.set(variableSymbol, content);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (ts.isIdentifier(node)) {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const symbol = typeChecker.getSymbolAtLocation(node);
|
||||
if (sourceMap.has(symbol)) {
|
||||
return ts.factory.createStringLiteral(sourceMap.get(symbol));
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
return ts.visitEachChild(node, visitor, context);
|
||||
};
|
||||
|
||||
return ts.visitNode(sourceFile, visitor);
|
||||
};
|
||||
|
||||
module.exports = transformerProgram;
|
||||
8
packages/internal/vite/markdown-literals.js
Normal file
8
packages/internal/vite/markdown-literals.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = () => ({
|
||||
name: 'markdown-literals',
|
||||
async load(id) {
|
||||
if (id.endsWith('.md')) {
|
||||
return `export default 'Mockup text';`;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -10,6 +10,10 @@
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAOwAAADsAEnxA+tAAABKklEQVQ4jcWTvUoDURCFv/y0A2tnZ95AW7FZwQdQSO9aRLAJbp0mPkGCTSCBmPQW8Q1SuKTU4AvkEeQO2K6MuSFmN+pCCg9cLhdmzpwzh1tK05RdUN6p+yeCftKK+kmrW4SguvGaNc3PGGRUVEE18x4Dl9dlheP76OZxMQUCIOzVa++/W2jENYaV7oqEWTMETMmhv7fi+w4i4IVhxaaeAq+9es0aL4CJqoaqOsmSrGNsxCZ16ideMeiMVPVrJyISqerC7IhIsN3CoGMeTfYceKARn6/sqOozcADkktmMcU3y5KeZrQQ4ARxwpqpts5O3kIEvGvnJ1vwB7PuquYgc5RVs4tZHeAe8WbOIlIA9r3IJU/DXcc61nXOpcy7I1hb9C5aOLTeHf/6NwCdua48fJxuYPgAAAABJRU5ErkJggg=="
|
||||
/>
|
||||
<link rel="stylesheet" href="{{style}}" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/highlightjs@9.16.2/styles/atom-one-dark.css"
|
||||
/>
|
||||
<title>Motion Canvas</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"@motion-canvas/core": "^12.1.0",
|
||||
"@preact/preset-vite": "^2.3.0",
|
||||
"clsx": "^1.2.1",
|
||||
"highlight.js": "^11.7.0",
|
||||
"preact": "10.7.3",
|
||||
"source-map-js": "^1.0.2",
|
||||
"typescript": "^4.6.4",
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
sizes="16x16"
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAOwAAADsAEnxA+tAAABKklEQVQ4jcWTvUoDURCFv/y0A2tnZ95AW7FZwQdQSO9aRLAJbp0mPkGCTSCBmPQW8Q1SuKTU4AvkEeQO2K6MuSFmN+pCCg9cLhdmzpwzh1tK05RdUN6p+yeCftKK+kmrW4SguvGaNc3PGGRUVEE18x4Dl9dlheP76OZxMQUCIOzVa++/W2jENYaV7oqEWTMETMmhv7fi+w4i4IVhxaaeAq+9es0aL4CJqoaqOsmSrGNsxCZ16ideMeiMVPVrJyISqerC7IhIsN3CoGMeTfYceKARn6/sqOozcADkktmMcU3y5KeZrQQ4ARxwpqpts5O3kIEvGvnJ1vwB7PuquYgc5RVs4tZHeAe8WbOIlIA9r3IJU/DXcc61nXOpcy7I1hb9C5aOLTeHf/6NwCdua48fJxuYPgAAAABJRU5ErkJggg=="
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/highlightjs@9.16.2/styles/atom-one-dark.css"
|
||||
/>
|
||||
<title>Motion Canvas</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -68,12 +68,8 @@ $colors: (
|
||||
.section {
|
||||
margin: 16px 8px 8px;
|
||||
|
||||
pre {
|
||||
background-color: var(--surface-color);
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
margin: 8px -8px;
|
||||
overflow-x: auto;
|
||||
p {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
code {
|
||||
@@ -82,6 +78,18 @@ $colors: (
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 8px -8px;
|
||||
overflow-x: auto;
|
||||
background-color: var(--surface-color);
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
code {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--theme);
|
||||
text-decoration: none;
|
||||
@@ -93,6 +101,26 @@ $colors: (
|
||||
}
|
||||
}
|
||||
|
||||
.sourceCode {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.viewSource {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -8px;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background-color: var(--surface-color);
|
||||
opacity: 0;
|
||||
transition: opacity 0.1s;
|
||||
|
||||
&:focus,
|
||||
.sourceCode:hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.entry {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
@@ -105,8 +133,12 @@ $colors: (
|
||||
|
||||
.link {
|
||||
font-size: 12px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
StackTraceEntry,
|
||||
} from '../../utils';
|
||||
|
||||
import {IconButton} from '../controls';
|
||||
import {OpenInNew} from '../icons';
|
||||
export interface SourceFrameProps {
|
||||
entry: StackTraceEntry;
|
||||
}
|
||||
@@ -18,21 +20,26 @@ export function SourceCodeFrame({entry}: SourceFrameProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<pre
|
||||
className={styles.code}
|
||||
onDblClick={async () => {
|
||||
if (entry) {
|
||||
await openFileInEditor(entry);
|
||||
}
|
||||
}}
|
||||
onMouseDown={e => {
|
||||
// Prevent selection when double-clicking.
|
||||
if (e.detail > 1) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{frame ?? 'Could not load the source code.'}
|
||||
</pre>
|
||||
<div className={styles.sourceCode}>
|
||||
<pre>
|
||||
<code
|
||||
className="language-ts"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: frame ?? 'Could not load the source code.',
|
||||
}}
|
||||
/>
|
||||
</pre>
|
||||
<IconButton
|
||||
title="Go to source"
|
||||
className={styles.viewSource}
|
||||
onClick={async () => {
|
||||
if (entry) {
|
||||
await openFileInEditor(entry);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<OpenInNew />
|
||||
</IconButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ export function StackTrace({entries}: StackTraceProps) {
|
||||
{entry.isExternal ? (
|
||||
`${entry.file}:${entry.line}:${entry.column}`
|
||||
) : (
|
||||
<span
|
||||
<button
|
||||
className={styles.link}
|
||||
onClick={() => openFileInEditor(entry)}
|
||||
>
|
||||
{entry.file}:{entry.line}:{entry.column}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
)
|
||||
</div>
|
||||
|
||||
@@ -1,36 +1,15 @@
|
||||
.iconCheckbox {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.iconInput {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.iconLabel {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
color: rgba(255, 255, 255, 0.54);
|
||||
|
||||
&.main {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.iconInput + &:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.iconInput:checked + & {
|
||||
&.checked {
|
||||
color: var(--theme);
|
||||
|
||||
&:hover {
|
||||
color: var(--theme);
|
||||
}
|
||||
|
||||
&.main {
|
||||
color: #fff;
|
||||
}
|
||||
@@ -39,8 +18,6 @@
|
||||
|
||||
.iconButton {
|
||||
-webkit-appearance: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
|
||||
@@ -7,13 +7,19 @@ interface IconButtonProps {
|
||||
title?: string;
|
||||
onClick?: () => void;
|
||||
children: ComponentChildren;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function IconButton({children, onClick, title}: IconButtonProps) {
|
||||
export function IconButton({
|
||||
children,
|
||||
onClick,
|
||||
title,
|
||||
className,
|
||||
}: IconButtonProps) {
|
||||
return (
|
||||
<button
|
||||
title={title}
|
||||
className={clsx(styles.iconButton)}
|
||||
className={clsx(styles.iconButton, className)}
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
>
|
||||
|
||||
@@ -2,12 +2,12 @@ import styles from './Controls.module.scss';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import {ComponentChildren} from 'preact';
|
||||
import {IconButton} from './IconButton';
|
||||
|
||||
interface IconCheckboxProps {
|
||||
children: ComponentChildren;
|
||||
titleOn?: string;
|
||||
titleOff?: string;
|
||||
id: string;
|
||||
onChange?: (value: boolean) => void;
|
||||
checked?: boolean;
|
||||
main?: boolean;
|
||||
@@ -17,29 +17,21 @@ export function IconCheckbox({
|
||||
children,
|
||||
titleOn,
|
||||
titleOff,
|
||||
id,
|
||||
onChange,
|
||||
checked = false,
|
||||
main = false,
|
||||
}: IconCheckboxProps) {
|
||||
return (
|
||||
<div className={styles.iconCheckbox}>
|
||||
<label
|
||||
title={titleOff && !checked ? titleOff : titleOn}
|
||||
className={clsx(styles.iconLabel, main && styles.main)}
|
||||
htmlFor={id}
|
||||
>
|
||||
<input
|
||||
className={styles.iconInput}
|
||||
type="checkbox"
|
||||
id={id}
|
||||
checked={checked}
|
||||
onChange={event => {
|
||||
onChange?.((event.target as HTMLInputElement).checked);
|
||||
}}
|
||||
/>
|
||||
{children}
|
||||
</label>
|
||||
</div>
|
||||
<IconButton
|
||||
className={clsx(
|
||||
styles.iconCheckbox,
|
||||
main && styles.main,
|
||||
checked && styles.checked,
|
||||
)}
|
||||
title={titleOff && !checked ? titleOff : titleOn}
|
||||
onClick={() => onChange?.(!checked)}
|
||||
>
|
||||
{children}
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ export interface ToggleProps {
|
||||
|
||||
export function Toggle({open, onToggle}: ToggleProps) {
|
||||
return (
|
||||
<div
|
||||
<button
|
||||
className={clsx(styles.toggle, open && styles.open)}
|
||||
onClick={() => onToggle(!open)}
|
||||
>
|
||||
<ChevronRight />
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
7
packages/ui/src/components/icons/OpenInNew.tsx
Normal file
7
packages/ui/src/components/icons/OpenInNew.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
export function OpenInNew() {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ export * from './Clear';
|
||||
export * from './DragIndicator';
|
||||
export * from './Locate';
|
||||
export * from './MotionCanvas';
|
||||
export * from './OpenInNew';
|
||||
export * from './Pause';
|
||||
export * from './PhotoCamera';
|
||||
export * from './PlayArrow';
|
||||
|
||||
@@ -71,7 +71,6 @@ export function PlaybackControls() {
|
||||
onChange={speed => player.setSpeed(speed)}
|
||||
/>
|
||||
<IconCheckbox
|
||||
id={'audio'}
|
||||
titleOn="Mute audio"
|
||||
titleOff="Unmute audio"
|
||||
checked={!state.muted}
|
||||
@@ -86,7 +85,6 @@ export function PlaybackControls() {
|
||||
<SkipPrevious />
|
||||
</IconButton>
|
||||
<IconCheckbox
|
||||
id={'play'}
|
||||
main
|
||||
titleOn="Play"
|
||||
titleOff="Pause"
|
||||
@@ -99,7 +97,6 @@ export function PlaybackControls() {
|
||||
<SkipNext />
|
||||
</IconButton>
|
||||
<IconCheckbox
|
||||
id={'loop'}
|
||||
titleOn="Loop video"
|
||||
checked={state.loop}
|
||||
onChange={() => player.toggleLoop()}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {SourceMapConsumer} from 'source-map-js';
|
||||
import {withLoader} from './withLoader';
|
||||
import highlight from 'highlight.js';
|
||||
|
||||
const externalFileRegex = /^\/(@fs|@id|node_modules)\//;
|
||||
const stackTraceRegex = navigator.userAgent.toLowerCase().includes('chrome')
|
||||
@@ -100,13 +101,16 @@ export function getSourceCodeFrame(entry: StackTraceEntry): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sourceLines = source.split('\n');
|
||||
const {line, column} = entry;
|
||||
const lastLine = line + 2;
|
||||
const spacing = lastLine.toString().length;
|
||||
const formatted = sourceLines
|
||||
.slice(line - 1, lastLine)
|
||||
.map((text, index) => `${line + index} | ${text}`);
|
||||
const sourceLines = source.split('\n').slice(line - 1, lastLine);
|
||||
|
||||
const code = highlight
|
||||
.highlight('typescript', sourceLines.join('\n'))
|
||||
.value.split('\n');
|
||||
|
||||
const formatted = code.map((text, index) => `${line + index} | ${text}`);
|
||||
formatted.splice(1, 0, `${' '.repeat(spacing)} | ${' '.repeat(column)}^`);
|
||||
return formatted.join('\n');
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"author": "motion-canvas",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"watch": "tsc -w"
|
||||
"build": "ttsc",
|
||||
"watch": "ttsc -w"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com/motion-canvas"
|
||||
@@ -23,6 +23,7 @@
|
||||
"vite": "3.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@motion-canvas/internal": "0.0.0",
|
||||
"@types/mime-types": "^2.1.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.9"
|
||||
|
||||
8
packages/vite-plugin/src/__logs__/project-instance.md
Normal file
8
packages/vite-plugin/src/__logs__/project-instance.md
Normal file
@@ -0,0 +1,8 @@
|
||||
Use the `makeProject()` function instead:
|
||||
|
||||
```ts
|
||||
import {makeProject} from '@motion-canvas/core';
|
||||
export default makeProject({
|
||||
// Configuration and scenes go here.
|
||||
});
|
||||
```
|
||||
1
packages/vite-plugin/src/globals.d.ts
vendored
Normal file
1
packages/vite-plugin/src/globals.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="@motion-canvas/internal" />
|
||||
@@ -3,6 +3,7 @@ import path from 'path';
|
||||
import fs from 'fs';
|
||||
import {Readable} from 'stream';
|
||||
import mime from 'mime-types';
|
||||
import projectInstance from './__logs__/project-instance.md';
|
||||
|
||||
export interface MotionCanvasPluginConfig {
|
||||
/**
|
||||
@@ -194,7 +195,7 @@ export default ({
|
||||
` config.name = '${name}';`,
|
||||
` config.logger.warn({`,
|
||||
` message: 'A project instance was exported instead of a project factory.',`,
|
||||
` remarks: \`Use the <code>makeProject()</code> function instead:<pre>import {makeProject} from '@motion-canvas/core';\nexport default makeProject({\n // Configuration and scenes go here.\n});</pre>\`,`,
|
||||
` remarks: \`${projectInstance}\`,`,
|
||||
` stack: config.creationStack,`,
|
||||
` });`,
|
||||
` return config;`,
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
"target": "es2021",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"plugins": [
|
||||
{
|
||||
"transform": "@motion-canvas/internal/transformers/markdown-literals.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user