├── public ├── desktop.png ├── desktop2.png └── mobile.png ├── postcss.config.js ├── .idea ├── .gitignore ├── vcs.xml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml └── shadcn-comments.iml ├── examples └── vite-tailwind-app │ ├── postcss.config.js │ ├── vite.config.ts │ ├── tailwind.config.js │ ├── tsconfig.node.json │ ├── src │ ├── main.tsx │ ├── App.tsx │ ├── App.css │ ├── index.css │ ├── theme-provider.tsx │ └── DemoComment.tsx │ ├── .gitignore │ ├── index.html │ ├── .eslintrc.cjs │ ├── tsconfig.json │ └── package.json ├── src ├── types │ ├── user.ts │ └── comment.ts ├── index.ts ├── lib │ └── utils.ts ├── components │ ├── PreviewComment.tsx │ ├── Input.tsx │ ├── EmojiSelect.tsx │ ├── Popover.tsx │ ├── EditorCommentStyle2.tsx │ ├── Avatar.tsx │ ├── Alert.tsx │ ├── Button.tsx │ ├── DropdownMenu.tsx │ ├── EditingEditorComment.tsx │ ├── EditorComment.tsx │ └── CommentSection.tsx ├── index.css └── mdx-style.css ├── .eslintrc.js ├── tsconfig.json ├── .eslintrc.cjs ├── vite.config.ts ├── LICENSE ├── .github └── workflows │ └── actions.yml ├── package.json ├── tailwind.config.js ├── .gitignore └── README.md /public/desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tecklens/shadcn-comments/HEAD/public/desktop.png -------------------------------------------------------------------------------- /public/desktop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tecklens/shadcn-comments/HEAD/public/desktop2.png -------------------------------------------------------------------------------- /public/mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tecklens/shadcn-comments/HEAD/public/mobile.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/types/user.ts: -------------------------------------------------------------------------------- 1 | 2 | export type User = { 3 | id: string, 4 | fullName: string, 5 | userProfile?: string, 6 | avatarUrl?: string, 7 | } 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } -------------------------------------------------------------------------------- /examples/vite-tailwind-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import './App.css' 2 | import 'shadcn-comments/dist/style.css'; 3 | import DemoComment from "./DemoComment.tsx"; 4 | import {ThemeProvider} from "./theme-provider.tsx"; 5 | 6 | export default function App() { 7 | 8 | return ( 9 | 10 | 11 | 12 | ) 13 | } 14 | 15 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export {Button, buttonVariants, type ButtonProps} from './components/Button'; 2 | export {Avatar, AvatarFallback, AvatarImage} from './components/Avatar'; 3 | export {Alert, AlertDescription, AlertTitle} from './components/Alert'; 4 | export {Input} from './components/Input'; 5 | export {EditorComment} from './components/EditorComment'; 6 | export {CommentSection} from './components/CommentSection'; 7 | export * from './types/comment' 8 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Shadcn Comments 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es2020: true }, 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:react-hooks/recommended', 7 | ], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 10 | plugins: ['react-refresh'], 11 | rules: { 12 | 'react-refresh/only-export-components': 'warn', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2020: true 5 | }, 6 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended'], 7 | parser: '@typescript-eslint/parser', 8 | parserOptions: { 9 | ecmaVersion: 'latest', 10 | sourceType: 'module' 11 | }, 12 | plugins: ['react-refresh'], 13 | rules: { 14 | 'react-refresh/only-export-components': 'warn' 15 | }, 16 | ignorePatterns: ["**/node_modules/**"] 17 | }; -------------------------------------------------------------------------------- /.idea/shadcn-comments.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | 8 | export function makeid(length: number) { 9 | let result = ''; 10 | const characters = 'abcdefghijklmnopqrstuvwxyz'.toUpperCase(); 11 | const charactersLength = characters.length; 12 | let counter = 0; 13 | while (counter < length) { 14 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 15 | counter += 1; 16 | } 17 | return result; 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "react-jsxdev", 17 | "outDir": "dist", 18 | "declaration": true, 19 | "declarationMap": true, 20 | }, 21 | "include": ["./src"] 22 | } 23 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "noEmit": true, 14 | "jsx": "react-jsx", 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "include": ["src"], 23 | "references": [{ "path": "./tsconfig.node.json" }] 24 | } 25 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2020: true 5 | }, 6 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended'], 7 | parser: '@typescript-eslint/parser', 8 | parserOptions: { 9 | ecmaVersion: 'latest', 10 | sourceType: 'module' 11 | }, 12 | plugins: ['react-refresh'], 13 | rules: { 14 | 'react-refresh/only-export-components': 'warn', 15 | '@typescript-eslint/no-empty-function': 'off', 16 | '@typescript-eslint/no-explicit-any': 'off', 17 | '@typescript-eslint/no-unused-vars': 'off', 18 | '@typescript-eslint/no-empty-interface': 'off', 19 | '@typescript-eslint/ban-ts-comment': 'off' 20 | }, 21 | ignorePatterns: ["**/node_modules/**"] 22 | }; -------------------------------------------------------------------------------- /examples/vite-tailwind-app/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | } 5 | 6 | .logo { 7 | height: 6em; 8 | padding: 1.5em; 9 | will-change: filter; 10 | transition: filter 300ms; 11 | } 12 | .logo:hover { 13 | filter: drop-shadow(0 0 2em #646cffaa); 14 | } 15 | .logo.react:hover { 16 | filter: drop-shadow(0 0 2em #61dafbaa); 17 | } 18 | 19 | @keyframes logo-spin { 20 | from { 21 | transform: rotate(0deg); 22 | } 23 | to { 24 | transform: rotate(360deg); 25 | } 26 | } 27 | 28 | @media (prefers-reduced-motion: no-preference) { 29 | a:nth-of-type(2) .logo { 30 | animation: logo-spin infinite 20s linear; 31 | } 32 | } 33 | 34 | .card { 35 | padding: 2em; 36 | } 37 | 38 | .read-the-docs { 39 | color: #888; 40 | } 41 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { resolve } from 'path' 3 | // @ts-ignore 4 | import { peerDependencies, dependencies } from './package.json' 5 | import react from '@vitejs/plugin-react' 6 | import dts from 'vite-plugin-dts'; 7 | 8 | export default defineConfig({ 9 | publicDir: false, 10 | plugins: [ 11 | react({ 12 | 'jsxRuntime': 'classic' 13 | }), 14 | dts({ 15 | include: ['src/**/*'], 16 | }) 17 | ], 18 | build: { 19 | lib: { 20 | entry: resolve(__dirname, 'src', 'index.ts'), 21 | formats: ['es', 'cjs'], 22 | fileName: (ext) => `index.${ext}.js`, 23 | }, 24 | rollupOptions: { 25 | external: [...Object.keys(peerDependencies), ...Object.keys(dependencies)], 26 | output: { preserveModules: true, exports: 'named' } 27 | }, 28 | 29 | target: 'esnext', 30 | sourcemap: true 31 | } 32 | }) -------------------------------------------------------------------------------- /src/components/PreviewComment.tsx: -------------------------------------------------------------------------------- 1 | import type {ReactNode} from "react"; 2 | import React, {useEffect, useState} from "react"; 3 | import {Fragment, jsx, jsxs} from "react/jsx-runtime"; 4 | import type {EvaluateOptions} from "@mdx-js/mdx"; 5 | import {evaluate} from "@mdx-js/mdx"; 6 | import type {MDXProps} from "mdx/types"; 7 | 8 | type ReactMDXContent = (props: MDXProps) => ReactNode; 9 | type Runtime = Pick; 10 | 11 | const runtime = { jsx, jsxs, Fragment } as Runtime; 12 | 13 | const PreviewComment: any = ({ source = "hêlo" }) => { 14 | const [MdxContent, setMdxContent] = useState(() => () => null); 15 | 16 | useEffect(() => { 17 | evaluate(source, runtime).then(r => { 18 | setMdxContent(() => r.default) 19 | }); 20 | }, [source]); 21 | 22 | // @ts-ignore 23 | return ; 24 | }; 25 | 26 | export default PreviewComment -------------------------------------------------------------------------------- /src/components/Input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "../lib/utils" 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ) 21 | } 22 | ) 23 | Input.displayName = "Input" 24 | 25 | export { Input } 26 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-tailwind-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "shadcn-comments": "file:../.." 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.2.25", 19 | "@types/react-dom": "^18.0.11", 20 | "@typescript-eslint/eslint-plugin": "^5.57.1", 21 | "@typescript-eslint/parser": "^5.57.1", 22 | "@vitejs/plugin-react": "^4.0.0", 23 | "autoprefixer": "^10.4.14", 24 | "eslint": "^8.38.0", 25 | "eslint-plugin-react-hooks": "^4.6.0", 26 | "eslint-plugin-react-refresh": "^0.3.4", 27 | "postcss": "^8.4.47", 28 | "tailwindcss": "^3.3.2", 29 | "typescript": "^5.0.2", 30 | "vite": "^5.4.6" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Rajesh Babu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/EmojiSelect.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import {ACTIONS, ACTIONS_TYPE} from "../types/comment"; 3 | 4 | interface EmojiSelectProps { 5 | className?: string; 6 | value?: string[]; 7 | onSelect: (id: string[], changeValue: ACTIONS_TYPE) => void; 8 | onUnSelect: (id: string[], changeValue: ACTIONS_TYPE) => void; 9 | } 10 | 11 | export default function EmojiSelect({className = '', value, onSelect, onUnSelect}: EmojiSelectProps) { 12 | return ( 13 |
14 | { 15 | ACTIONS.map(e => ( 16 |
{ 20 | if (value?.includes(e.id)) 21 | onUnSelect(value?.filter(f => f != e.id), e.id) 22 | else onSelect(value ? [...value, e.id] : [e.id], e.id) 23 | }} 24 | > 25 | {e.emoji} 26 |
27 | )) 28 | } 29 |
30 | ) 31 | } -------------------------------------------------------------------------------- /src/components/Popover.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as PopoverPrimitive from "@radix-ui/react-popover" 3 | 4 | import { cn } from "../lib/utils" 5 | 6 | const Popover = PopoverPrimitive.Root 7 | 8 | const PopoverTrigger = PopoverPrimitive.Trigger 9 | 10 | const PopoverAnchor = PopoverPrimitive.Anchor 11 | 12 | const PopoverContent = React.forwardRef< 13 | React.ElementRef, 14 | React.ComponentPropsWithoutRef 15 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 16 | 17 | 27 | 28 | )) 29 | PopoverContent.displayName = PopoverPrimitive.Content.displayName 30 | 31 | export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } 32 | -------------------------------------------------------------------------------- /src/types/comment.ts: -------------------------------------------------------------------------------- 1 | import {User} from "./user"; 2 | 3 | export const LIST_EMOJI = [ 4 | '👍', 5 | '👎', 6 | '😄', 7 | '🎉', 8 | '😕', 9 | '❤️', 10 | '🚀', 11 | '👀', 12 | ] 13 | 14 | export enum ACTIONS_TYPE { 15 | THUMB_UP = 'THUMB_UP', 16 | THUMB_DOWN = 'THUMB_DOWN', 17 | LAUGH = 'LAUGH', 18 | HOORAY = 'HOORAY', 19 | CONFUSED = 'CONFUSED', 20 | HEART = 'HEART', 21 | ROCKET = 'ROCKET', 22 | EYE = 'EYE', 23 | UPVOTE = 'UPVOTE' 24 | } 25 | 26 | export const ACTIONS = [ 27 | { 28 | id: ACTIONS_TYPE.THUMB_UP, 29 | emoji: LIST_EMOJI[0] 30 | }, 31 | { 32 | id: ACTIONS_TYPE.THUMB_DOWN, 33 | emoji: LIST_EMOJI[1] 34 | }, 35 | { 36 | id: ACTIONS_TYPE.LAUGH, 37 | emoji: LIST_EMOJI[2] 38 | }, 39 | { 40 | id: ACTIONS_TYPE.HOORAY, 41 | emoji: LIST_EMOJI[3] 42 | }, 43 | { 44 | id: ACTIONS_TYPE.CONFUSED, 45 | emoji: LIST_EMOJI[4] 46 | }, 47 | { 48 | id: ACTIONS_TYPE.HEART, 49 | emoji: LIST_EMOJI[5] 50 | }, 51 | { 52 | id: ACTIONS_TYPE.ROCKET, 53 | emoji: LIST_EMOJI[6] 54 | }, 55 | { 56 | id: ACTIONS_TYPE.EYE, 57 | emoji: LIST_EMOJI[7] 58 | }, 59 | ] 60 | 61 | export type Comment = { 62 | user: User, 63 | id: string, 64 | parentId?: string; 65 | text: string, 66 | replies?: Comment[], 67 | createdAt: Date; 68 | actions?: {[key in ACTIONS_TYPE]: number}; 69 | selectedActions?: ACTIONS_TYPE[]; 70 | allowUpvote?: boolean; 71 | } -------------------------------------------------------------------------------- /src/components/EditorCommentStyle2.tsx: -------------------------------------------------------------------------------- 1 | import React, {useState} from "react"; 2 | import {Avatar, AvatarFallback, AvatarImage} from "./Avatar"; 3 | import {Input} from "./Input"; 4 | import {Camera, SendIcon, SmileIcon} from "lucide-react"; 5 | import {User} from "../types/user"; 6 | 7 | interface EditorCommentStyle2Props { 8 | value?: string; 9 | onChange?: (val: string) => void; 10 | currentUser: User; 11 | } 12 | 13 | export const EditorCommentStyle2 = ({ 14 | value = '', 15 | onChange = () => { 16 | }, 17 | currentUser, 18 | }: EditorCommentStyle2Props) => { 19 | const [tempValue, setTempValue] = useState('') 20 | return ( 21 |
22 | 23 | 24 | CN 25 | 26 | 27 |
28 | setTempValue(v.target.value)} 33 | onKeyDown={e => { 34 | if (e.code === 'Enter') { 35 | onChange(tempValue) 36 | setTempValue('') 37 | } 38 | }} 39 | /> 40 |
41 |
42 | ) 43 | } -------------------------------------------------------------------------------- /examples/vite-tailwind-app/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 7 | line-height: 1.5; 8 | font-weight: 400; 9 | 10 | color-scheme: light dark; 11 | color: rgba(255, 255, 255, 0.87); 12 | background-color: #242424; 13 | 14 | font-synthesis: none; 15 | text-rendering: optimizeLegibility; 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | -webkit-text-size-adjust: 100%; 19 | } 20 | 21 | a { 22 | font-weight: 500; 23 | color: #646cff; 24 | text-decoration: inherit; 25 | } 26 | a:hover { 27 | color: #535bf2; 28 | } 29 | 30 | body { 31 | margin: 0; 32 | display: flex; 33 | place-items: center; 34 | min-width: 320px; 35 | min-height: 100vh; 36 | } 37 | 38 | h1 { 39 | font-size: 3.2em; 40 | line-height: 1.1; 41 | } 42 | 43 | button { 44 | border-radius: 8px; 45 | border: 1px solid transparent; 46 | padding: 0.6em 1.2em; 47 | font-size: 1em; 48 | font-weight: 500; 49 | font-family: inherit; 50 | background-color: #1a1a1a; 51 | cursor: pointer; 52 | transition: border-color 0.25s; 53 | } 54 | button:hover { 55 | border-color: #646cff; 56 | } 57 | button:focus, 58 | button:focus-visible { 59 | outline: 4px auto -webkit-focus-ring-color; 60 | } 61 | 62 | @media (prefers-color-scheme: light) { 63 | :root { 64 | color: #213547; 65 | background-color: #ffffff; 66 | } 67 | a:hover { 68 | color: #747bff; 69 | } 70 | button { 71 | background-color: #f9f9f9; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/components/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as AvatarPrimitive from "@radix-ui/react-avatar" 3 | 4 | import { cn } from "../lib/utils"; 5 | 6 | const Avatar = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >(({ className, ...props }, ref) => ( 10 | 18 | )) 19 | Avatar.displayName = AvatarPrimitive.Root.displayName 20 | 21 | const AvatarImage = React.forwardRef< 22 | React.ElementRef, 23 | React.ComponentPropsWithoutRef 24 | >(({ className, ...props }, ref) => ( 25 | 30 | )) 31 | AvatarImage.displayName = AvatarPrimitive.Image.displayName 32 | 33 | const AvatarFallback = React.forwardRef< 34 | React.ElementRef, 35 | React.ComponentPropsWithoutRef 36 | >(({ className, ...props }, ref) => ( 37 | 45 | )) 46 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName 47 | 48 | export { Avatar, AvatarImage, AvatarFallback } 49 | -------------------------------------------------------------------------------- /.github/workflows/actions.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ['main'] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: 'pages' 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Single deploy job since we're just deploying 25 | deploy: 26 | environment: 27 | name: github-pages 28 | url: ${{ steps.deployment.outputs.page_url }} 29 | runs-on: ubuntu-latest 30 | defaults: 31 | run: 32 | working-directory: ./examples/vite-tailwind-app 33 | steps: 34 | - name: Checkout 35 | uses: actions/checkout@v4 36 | - name: Set up Node 37 | uses: actions/setup-node@v4 38 | with: 39 | node-version: 18 40 | cache: 'npm' 41 | - name: Install dependencies 42 | run: npm i 43 | - name: Build 44 | run: npm run build 45 | - name: Setup Pages 46 | uses: actions/configure-pages@v4 47 | - name: Upload artifact 48 | uses: actions/upload-pages-artifact@v3 49 | with: 50 | # Upload dist folder 51 | path: './examples/vite-tailwind-app/dist' 52 | - name: Deploy to GitHub Pages 53 | id: deployment 54 | uses: actions/deploy-pages@v4 55 | -------------------------------------------------------------------------------- /src/components/Alert.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "../lib/utils" 5 | 6 | const alertVariants = cva( 7 | "relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11", 8 | { 9 | variants: { 10 | variant: { 11 | default: "bg-background text-foreground", 12 | destructive: 13 | "text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive", 14 | }, 15 | }, 16 | defaultVariants: { 17 | variant: "default", 18 | }, 19 | } 20 | ) 21 | 22 | const Alert = React.forwardRef< 23 | HTMLDivElement, 24 | React.HTMLAttributes & VariantProps 25 | >(({ className, variant, ...props }, ref) => ( 26 |
32 | )) 33 | Alert.displayName = "Alert" 34 | 35 | const AlertTitle = React.forwardRef< 36 | HTMLParagraphElement, 37 | React.HTMLAttributes 38 | >(({ className, ...props }, ref) => ( 39 |
44 | )) 45 | AlertTitle.displayName = "AlertTitle" 46 | 47 | const AlertDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 |
56 | )) 57 | AlertDescription.displayName = "AlertDescription" 58 | 59 | export { Alert, AlertTitle, AlertDescription } 60 | -------------------------------------------------------------------------------- /src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "../lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "underline-offset-4 hover:underline text-primary", 21 | }, 22 | size: { 23 | default: "h-9 px-4 py-2", 24 | sm: "h-8 rounded-md px-3 text-xs", 25 | lg: "h-10 rounded-md px-8", 26 | icon: "h-9 w-9", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ) 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button" 45 | return ( 46 | 51 | ) 52 | } 53 | ) 54 | Button.displayName = "Button" 55 | 56 | export { Button, buttonVariants } 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shadcn-comments", 3 | "description": "Shadcn React component library for a functioning comments section", 4 | "private": false, 5 | "version": "1.0.5", 6 | "type": "module", 7 | "main": "dist/index.cjs.js", 8 | "module": "dist/index.es.js", 9 | "types": "dist/index.d.ts", 10 | "sideEffects": false, 11 | "files": [ 12 | "dist" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/tecklens/shadcn-comments" 17 | }, 18 | "scripts": { 19 | "dev": "vite", 20 | "build": "tsc && vite build && npm run build:styles", 21 | "build:styles": "postcss ./src/index.css -o ./dist/style.css && postcss ./src/mdx-style.css -o ./dist/mdx-style.css", 22 | "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0" 23 | }, 24 | "peerDependencies": { 25 | "react": "^18.3.1", 26 | "react-dom": "^18.3.1" 27 | }, 28 | "dependencies": { 29 | "@mdx-js/mdx": "^3.0.1", 30 | "@mdx-js/react": "^3.0.1", 31 | "@mdxeditor/editor": "^3.11.3", 32 | "@radix-ui/react-avatar": "^1.0.3", 33 | "@radix-ui/react-popover": "^1.1.2", 34 | "@radix-ui/react-slot": "^1.0.2", 35 | "class-variance-authority": "^0.6.0", 36 | "clsx": "^1.2.1", 37 | "date-fns": "^3.6.0", 38 | "lucide-react": "^0.453.0", 39 | "tailwind-merge": "^1.12.0", 40 | "tailwindcss-animate": "^1.0.5" 41 | }, 42 | "devDependencies": { 43 | "@types/react": "^18.3.5", 44 | "@types/react-dom": "^18.3.0", 45 | "@typescript-eslint/eslint-plugin": "^5.57.1", 46 | "@typescript-eslint/parser": "^5.57.1", 47 | "@vitejs/plugin-react": "^4.0.0", 48 | "autoprefixer": "^10.4.14", 49 | "eslint": "^8.38.0", 50 | "eslint-plugin-react-hooks": "^4.6.0", 51 | "eslint-plugin-react-refresh": "^0.3.4", 52 | "postcss": "^8.4.47", 53 | "postcss-cli": "^10.1.0", 54 | "prop-types": "^15.8.1", 55 | "tailwindcss": "^3.3.2", 56 | "typescript": "^5.0.2", 57 | "vite": "^5.4.6", 58 | "vite-plugin-dts": "^2.3.0" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/vite-tailwind-app/src/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useEffect, useState } from 'react' 2 | 3 | type Theme = 'dark' | 'light' | 'system' 4 | 5 | type ThemeProviderProps = { 6 | children: React.ReactNode 7 | defaultTheme?: Theme 8 | storageKey?: string 9 | } 10 | 11 | type ThemeProviderState = { 12 | theme: Theme 13 | setTheme: (theme: Theme) => void 14 | } 15 | 16 | const initialState: ThemeProviderState = { 17 | theme: 'system', 18 | setTheme: () => null, 19 | } 20 | 21 | const ThemeProviderContext = createContext(initialState) 22 | 23 | export function ThemeProvider({ 24 | children, 25 | defaultTheme = 'system', 26 | storageKey = 'theme', 27 | ...props 28 | }: ThemeProviderProps) { 29 | const [theme, setTheme] = useState( 30 | () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, 31 | ) 32 | 33 | useEffect(() => { 34 | const root = window.document.documentElement 35 | 36 | root.classList.remove('light', 'dark') 37 | 38 | if (theme === 'system') { 39 | const systemTheme = window.matchMedia('(prefers-color-scheme: dark)') 40 | .matches 41 | ? 'dark' 42 | : 'light' 43 | 44 | root.classList.add(systemTheme) 45 | return 46 | } 47 | 48 | root.classList.add(theme) 49 | }, [theme]) 50 | 51 | const value = { 52 | theme, 53 | setTheme: (theme: Theme) => { 54 | localStorage.setItem(storageKey, theme) 55 | setTheme(theme) 56 | }, 57 | } 58 | 59 | return ( 60 | 61 |
62 | {children} 63 |
64 |
65 | ) 66 | } 67 | 68 | // eslint-disable-next-line react-refresh/only-export-components 69 | export const useTheme = () => { 70 | const context = useContext(ThemeProviderContext) 71 | 72 | if (context === undefined) 73 | throw new Error('useTheme must be used within a ThemeProvider') 74 | 75 | return context 76 | } 77 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const { fontFamily } = require("tailwindcss/defaultTheme") 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | darkMode: ["class"], 6 | content: ["./src/**/*.{js,ts,jsx,tsx}"], 7 | safelist: [ 8 | 'dark' 9 | ], 10 | theme: { 11 | container: { 12 | center: true, 13 | padding: "2rem", 14 | screens: { 15 | "2xl": "1400px", 16 | }, 17 | }, 18 | extend: { 19 | colors: { 20 | border: "hsl(var(--border))", 21 | input: "hsl(var(--input))", 22 | ring: "hsl(var(--ring))", 23 | background: "hsl(var(--background))", 24 | foreground: "hsl(var(--foreground))", 25 | primary: { 26 | DEFAULT: "hsl(var(--primary))", 27 | foreground: "hsl(var(--primary-foreground))", 28 | }, 29 | secondary: { 30 | DEFAULT: "hsl(var(--secondary))", 31 | foreground: "hsl(var(--secondary-foreground))", 32 | }, 33 | destructive: { 34 | DEFAULT: "hsl(var(--destructive))", 35 | foreground: "hsl(var(--destructive-foreground))", 36 | }, 37 | muted: { 38 | DEFAULT: "hsl(var(--muted))", 39 | foreground: "hsl(var(--muted-foreground))", 40 | }, 41 | accent: { 42 | DEFAULT: "hsl(var(--accent))", 43 | foreground: "hsl(var(--accent-foreground))", 44 | }, 45 | popover: { 46 | DEFAULT: "hsl(var(--popover))", 47 | foreground: "hsl(var(--popover-foreground))", 48 | }, 49 | card: { 50 | DEFAULT: "hsl(var(--card))", 51 | foreground: "hsl(var(--card-foreground))", 52 | }, 53 | }, 54 | borderRadius: { 55 | lg: `var(--radius)`, 56 | md: `calc(var(--radius) - 2px)`, 57 | sm: "calc(var(--radius) - 4px)", 58 | }, 59 | fontFamily: { 60 | sans: ["var(--font-sans)", ...fontFamily.sans], 61 | }, 62 | keyframes: { 63 | "accordion-down": { 64 | from: { height: 0 }, 65 | to: { height: "var(--radix-accordion-content-height)" }, 66 | }, 67 | "accordion-up": { 68 | from: { height: "var(--radix-accordion-content-height)" }, 69 | to: { height: 0 }, 70 | }, 71 | }, 72 | animation: { 73 | "accordion-down": "accordion-down 0.2s ease-out", 74 | "accordion-up": "accordion-up 0.2s ease-out", 75 | }, 76 | }, 77 | }, 78 | plugins: [require("tailwindcss-animate")], 79 | } 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # EditorComment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /src/components/DropdownMenu.tsx: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useRef, useState} from "react"; 2 | import {EllipsisVertical} from "lucide-react"; 3 | import {Comment} from "../types/comment"; 4 | import {User} from "../types/user"; 5 | 6 | export function DropdownMenu({comment, openEditor, currentUser, deleteComment}: { 7 | comment: Comment, 8 | openEditor: () => void, 9 | deleteComment: () => void, 10 | currentUser: User 11 | }) { 12 | const ref = useRef() 13 | const [open, setOpen] = useState(false) 14 | 15 | const copyToClipboard = async () => { 16 | const textToCopy = window.location.host + `#comment-${comment.id}`; 17 | // Navigator clipboard api needs a secure context (https) 18 | if (navigator.clipboard && window.isSecureContext) { 19 | await navigator.clipboard.writeText(textToCopy ?? ''); 20 | setOpen(false) 21 | } 22 | } 23 | 24 | const del = () => { 25 | setOpen(false) 26 | if (confirm('Are you sure you want to delete this?')) { 27 | deleteComment() 28 | } 29 | } 30 | 31 | useEffect(() => { 32 | /** 33 | * Alert if clicked on outside of element 34 | */ 35 | function handleClickOutside(event: any) { 36 | if (ref.current && !ref.current.contains(event.target)) { 37 | if (open) setOpen(false) 38 | } 39 | } 40 | 41 | // Bind the event listener 42 | document.addEventListener("mousedown", handleClickOutside); 43 | return () => { 44 | // Unbind the event listener on clean up 45 | document.removeEventListener("mousedown", handleClickOutside); 46 | }; 47 | }, [open, ref]); 48 | 49 | return ( 50 |
51 |
setOpen(!open)} className={'w-8 h-8 flex justify-center items-center cursor-pointer dropbtn'}> 52 | 53 |
54 |
57 |
61 |
Copy link
62 |
63 | {currentUser.id === comment.user.id &&
{ 65 | openEditor() 66 | setOpen(false) 67 | }} 68 | className={'px-3 py-2 text-sm hover:bg-blue-500 hover:text-white'} 69 | > 70 |
Edit
71 |
} 72 | {currentUser.id === comment.user.id &&
76 |
Delete
77 |
} 78 |
79 |
80 | ) 81 | } -------------------------------------------------------------------------------- /examples/vite-tailwind-app/src/DemoComment.tsx: -------------------------------------------------------------------------------- 1 | import {useState} from "react"; 2 | import {Terminal} from "lucide-react"; 3 | import {useTheme} from "./theme-provider.tsx"; 4 | import {Alert, AlertDescription, AlertTitle, Button, CommentSection, ACTIONS_TYPE} from 'shadcn-comments' 5 | 6 | export default function DemoComment() { 7 | const {theme, setTheme} = useTheme() 8 | const [value, setValue] = useState([ 9 | { 10 | user: { 11 | id: '1', 12 | userProfile: '', 13 | fullName: 'victorcesae', 14 | avatarUrl: '' 15 | }, 16 | id: '2', 17 | text: 'Another utility is to add text adornments, doing some simple typechecking so if a string is passed you can style a background, else render the react node.', 18 | replies: [], 19 | createdAt: new Date('2024-06-01'), 20 | selectedActions: [ACTIONS_TYPE.UPVOTE, ACTIONS_TYPE.ROCKET, ACTIONS_TYPE.HEART], 21 | actions: { 22 | [ACTIONS_TYPE.UPVOTE]: 1, 23 | [ACTIONS_TYPE.ROCKET]: 10, 24 | [ACTIONS_TYPE.HEART]: 10, 25 | } 26 | }, 27 | { 28 | user: { 29 | id: '4', 30 | userProfile: '', 31 | fullName: 'UltimateGG', 32 | avatarUrl: '' 33 | }, 34 | id: '3', 35 | text: 'Another utility is to add text adornments, doing some simple typechecking so if a string is passed you can style a background, else render the react node.', 36 | replies: [{ 37 | user: { 38 | id: '4', 39 | userProfile: '', 40 | fullName: 'UltimateGG', 41 | avatarUrl: '' 42 | }, 43 | id: '8', 44 | text: 'Another utility is to add text adornments', 45 | replies: [], 46 | createdAt: new Date('2024-09-02') 47 | }], 48 | createdAt: new Date('2024-09-01') 49 | } 50 | ]) 51 | 52 | const toggleDarkMode = () => { 53 | setTheme(theme === 'light' ? 'dark' : 'light'); 54 | }; 55 | 56 | return ( 57 |
58 |
59 |

60 | Built using shadcn-comments 61 |

62 |
63 | 64 |
65 |
66 | 67 | 68 | Heads up! 69 | 70 | You can add components and dependencies to your app using the cli. 71 | 72 | 73 |
74 |
75 | { 85 | setValue(val) 86 | }} 87 | className={''} 88 | allowUpVote={true} 89 | /> 90 |
91 | ) 92 | } -------------------------------------------------------------------------------- /src/components/EditingEditorComment.tsx: -------------------------------------------------------------------------------- 1 | import React, {useEffect, useState} from "react"; 2 | import { 3 | BlockTypeSelect, 4 | BoldItalicUnderlineToggles, 5 | CreateLink, 6 | headingsPlugin, 7 | imagePlugin, 8 | InsertImage, 9 | InsertTable, 10 | linkDialogPlugin, 11 | linkPlugin, 12 | listsPlugin, 13 | ListsToggle, 14 | markdownShortcutPlugin, 15 | MDXEditor, 16 | quotePlugin, 17 | Separator, 18 | tablePlugin, 19 | thematicBreakPlugin, 20 | toolbarPlugin, 21 | UndoRedo 22 | } from "@mdxeditor/editor"; 23 | import {Button} from "./Button"; 24 | import {User} from "../types/user"; 25 | 26 | interface EditorCommentProps { 27 | value?: string; 28 | onChange?: (val: string) => void; 29 | placeholder?: string, 30 | onUpload?: (image: File) => Promise; 31 | theme: 'light' | 'dark' | 'system', 32 | currentUser: User; 33 | } 34 | 35 | export const EditingEditorComment = ({ 36 | value = '', onChange = () => { 37 | }, 38 | placeholder = 'Add your comment here...', 39 | onUpload, 40 | theme, 41 | currentUser, 42 | }: EditorCommentProps) => { 43 | const [tempValue, setTempValue] = useState(value) 44 | 45 | return ( 46 |
47 |
48 |
49 | ( 58 |
59 | {' '} 60 | 61 | 62 | 63 | 64 | {/**/} 75 |
76 | 77 | 78 | 79 | 80 |
81 |
82 | ) 83 | }), 84 | headingsPlugin(), 85 | listsPlugin(), 86 | quotePlugin(), 87 | thematicBreakPlugin(), 88 | markdownShortcutPlugin(), 89 | tablePlugin(), 90 | imagePlugin({ 91 | imageUploadHandler: onUpload, 92 | }), 93 | linkPlugin(), 94 | linkDialogPlugin(), 95 | ]} 96 | /> 97 |
98 |
99 |
100 | 104 |
105 |
106 | ) 107 | } -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import "./mdx-style.css"; 2 | 3 | @tailwind base; 4 | @tailwind components; 5 | @tailwind utilities; 6 | 7 | @layer base { 8 | :root { 9 | --background: 0 0% 100%; 10 | --foreground: 222.2 47.4% 11.2%; 11 | 12 | --muted: 210 40% 96.1%; 13 | --muted-foreground: 215.4 16.3% 46.9%; 14 | 15 | --popover: 0 0% 100%; 16 | --popover-foreground: 222.2 47.4% 11.2%; 17 | 18 | --card: 0 0% 100%; 19 | --card-foreground: 222.2 47.4% 11.2%; 20 | 21 | --border: 214.3 31.8% 91.4%; 22 | --input: 214.3 31.8% 91.4%; 23 | 24 | --primary: 222.2 47.4% 11.2%; 25 | --primary-foreground: 210 40% 98%; 26 | 27 | --secondary: 210 40% 96.1%; 28 | --secondary-foreground: 222.2 47.4% 11.2%; 29 | 30 | --accent: 210 40% 96.1%; 31 | --accent-foreground: 222.2 47.4% 11.2%; 32 | 33 | --destructive: 0 100% 50%; 34 | --destructive-foreground: 210 40% 98%; 35 | 36 | --ring: 215 20.2% 65.1%; 37 | 38 | --radius: 0.5rem; 39 | 40 | --caret-bg: #f6f8fa; 41 | --caret-border: #d1d9e0; 42 | } 43 | 44 | .dark { 45 | --background: 224 71% 4%; 46 | --foreground: 213 31% 91%; 47 | 48 | --muted: 223 47% 11%; 49 | --muted-foreground: 215.4 16.3% 56.9%; 50 | 51 | --popover: 224 71% 4%; 52 | --popover-foreground: 215 20.2% 65.1%; 53 | 54 | --card: 224 71% 4%; 55 | --card-foreground: 213 31% 91%; 56 | 57 | --border: 216 34% 17%; 58 | --input: 216 34% 17%; 59 | 60 | --primary: 210 40% 98%; 61 | --primary-foreground: 222.2 47.4% 1.2%; 62 | 63 | --secondary: 222.2 47.4% 11.2%; 64 | --secondary-foreground: 210 40% 98%; 65 | 66 | --accent: 216 34% 17%; 67 | --accent-foreground: 210 40% 98%; 68 | 69 | --destructive: 0 63% 31%; 70 | --destructive-foreground: 210 40% 98%; 71 | 72 | --ring: 216 34% 17%; 73 | 74 | --radius: 0.5rem; 75 | 76 | --caret-bg: #3d444d; 77 | --caret-border: #d1d9e0; 78 | } 79 | } 80 | 81 | @layer base { 82 | * { 83 | @apply border-border; 84 | } 85 | 86 | body { 87 | @apply bg-background text-foreground; 88 | font-feature-settings: "rlig" 1, "calt" 1; 89 | } 90 | } 91 | 92 | .s-comment-card { 93 | position: relative; 94 | } 95 | 96 | .s-comment-card .user { 97 | background-color: var(--caret-bg); 98 | } 99 | 100 | .s-comment-card::before { 101 | background-color: var(--caret-border); 102 | color: var(--caret-bg); 103 | position: absolute; 104 | top: 11px; 105 | right: 100%; 106 | left: calc(0.5rem * -1); 107 | display: block; 108 | width: 8px; 109 | height: 16px; 110 | pointer-events: none; 111 | content: " "; 112 | clip-path: polygon(0 50%, 100% 0, 100% 100%); 113 | } 114 | 115 | .s-comment-card::after { 116 | margin-left: 1px; 117 | background-color: var(--caret-bg); 118 | position: absolute; 119 | top: 11px; 120 | right: 100%; 121 | left: calc(0.5rem * -1); 122 | display: block; 123 | width: 8px; 124 | height: 16px; 125 | pointer-events: none; 126 | content: " "; 127 | clip-path: polygon(0 50%, 100% 0, 100% 100%); 128 | } 129 | 130 | /* The container
- needed to position the dropdown content */ 131 | .dropdown { 132 | position: relative; 133 | display: inline-block; 134 | } 135 | 136 | /* Dropdown Content (Hidden by Default) */ 137 | .dropdown-content { 138 | display: none; 139 | position: absolute; 140 | background-color: var(--caret-bg); 141 | width: 160px; 142 | right: 0; 143 | box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); 144 | z-index: 3; 145 | } 146 | 147 | /* Change color of dropdown links on hover */ 148 | .dropdown-content a:hover {background-color: #f1f1f1} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shadcn Comments 2 | 3 | --- 4 | [Demo](https://shadcn-comment.pages.dev/) 5 | ## Install 6 | 7 | Install the latest version! 8 | 9 | ```shell 10 | npm i shadcn-comments 11 | ``` 12 | --- 13 | 14 | `shadcn-comments` is a simple but multi-functional shadcn-react comment section component that helps you create 15 | comments section similar to github for your React App. `shadcn-comments` is very useful for react beginners 16 | who want a comment section in their project but want to skip it's commplexity. 17 | This library will give a fully functional comment section with the 18 | following features: 19 | 20 | - User can reply to comments 21 | - User can edit his/her comments 22 | - User can delete his/her comments 23 | 24 | Live demo of the library: [here](#) 25 | 26 | --- 27 | 28 | ## Default Example 29 | 30 | You can find the source code [here](#) 31 | ### Mobile 32 | ![mobile](/public/mobile.png) 33 | ### Desktop (max-w-screen-md) 34 | ![desktop](/public/desktop.png) 35 | 36 | ### Desktop editing (max-w-screen-md) 37 | ![desktop - edit](/public/desktop2.png) 38 | 39 | --- 40 | 41 | ## Usage 42 | 43 | Following is a basic example to start testing the library in your project. This library works on a user basis system and here are a few important points to remember: 44 | 45 | | Props | Data Types | Default | 46 | |--------------|-------------------------------|---------| 47 | | theme | 'light' \| 'dark' \| 'system' | light | 48 | | currentUser | [User](#types) | default | 49 | | value | [Comment\[\]](#types) | [] | 50 | | onChange | (comments: Comment[]) => void | | 51 | | className | string | | 52 | | allowUpVote | boolean | false | 53 | | onVoteChange | (checked: boolean) => void | false | 54 | 55 | ```tsx 56 | import {useState} from "react"; 57 | import {Terminal} from "lucide-react"; 58 | import {useTheme} from "./theme-provider.tsx"; 59 | import {Alert, AlertDescription, AlertTitle, Button, CommentSection, ACTIONS_TYPE} from 'shadcn-comments' 60 | 61 | export default function DemoComment() { 62 | const {theme, setTheme} = useTheme() 63 | const [value, setValue] = useState([ 64 | { 65 | user: { 66 | id: '1', 67 | userProfile: '', 68 | fullName: 'victorcesae', 69 | avatarUrl: '' 70 | }, 71 | id: '2', 72 | text: 'Another utility is to add text adornments, doing some simple typechecking so if a string is passed you can style a background, else render the react node.', 73 | replies: [], 74 | createdAt: new Date('2024-06-01'), 75 | selectedActions: [ACTIONS_TYPE.UPVOTE, ACTIONS_TYPE.ROCKET, ACTIONS_TYPE.HEART], 76 | actions: { 77 | [ACTIONS_TYPE.UPVOTE]: 1, 78 | [ACTIONS_TYPE.ROCKET]: 10, 79 | [ACTIONS_TYPE.HEART]: 10, 80 | } 81 | }, 82 | { 83 | user: { 84 | id: '4', 85 | userProfile: '', 86 | fullName: 'UltimateGG', 87 | avatarUrl: '' 88 | }, 89 | id: '3', 90 | text: 'Another utility is to add text adornments, doing some simple typechecking so if a string is passed you can style a background, else render the react node.', 91 | replies: [{ 92 | user: { 93 | id: '4', 94 | userProfile: '', 95 | fullName: 'UltimateGG', 96 | avatarUrl: '' 97 | }, 98 | id: '8', 99 | text: 'Another utility is to add text adornments', 100 | replies: [], 101 | createdAt: new Date('2024-09-02') 102 | }], 103 | createdAt: new Date('2024-09-01') 104 | } 105 | ]) 106 | 107 | const toggleDarkMode = () => { 108 | setTheme(theme === 'light' ? 'dark' : 'light'); 109 | }; 110 | 111 | return ( 112 |
113 |
114 |

115 | Built using shadcn-comments 116 |

117 |
118 | 119 |
120 |
121 | 122 | 123 | Heads up! 124 | 125 | You can add components and dependencies to your app using the cli. 126 | 127 | 128 |
129 |
130 | { 140 | setValue(val) 141 | }} 142 | className={''} 143 | allowUpVote={true} 144 | /> 145 |
146 | ) 147 | } 148 | ``` 149 | --- 150 | 151 | ### Types 152 | 153 | ```typescript 154 | // User 155 | export type User = { 156 | id: string, 157 | fullName: string, 158 | userProfile?: string, 159 | avatarUrl?: string, 160 | } 161 | ``` 162 | 163 | ```typescript 164 | // Comment 165 | export type Comment = { 166 | user: User, 167 | id: string, 168 | parentId?: string; 169 | text: string, 170 | replies?: Comment[], 171 | createdAt: Date; 172 | } 173 | ``` 174 | --- 175 | ## Change log 176 | 177 | v1.0.3: add edit/delete/copy link/actions emoji for comment 178 | --- 179 | 180 | ## License 181 | 182 | MIT © [dieptv1999](https://github.com/dieptv1999) -------------------------------------------------------------------------------- /src/components/CommentSection.tsx: -------------------------------------------------------------------------------- 1 | import React, {useState} from "react"; 2 | import {Avatar, AvatarFallback, AvatarImage} from "./Avatar"; 3 | import {ArrowUpIcon, CircleIcon, SmileIcon} from "lucide-react"; 4 | import {EditorComment} from "./EditorComment"; 5 | import {ACTIONS, ACTIONS_TYPE, Comment} from "../types/comment"; 6 | import {User} from "../types/user"; 7 | import {EditorCommentStyle2} from "./EditorCommentStyle2"; 8 | import {makeid} from "../lib/utils"; 9 | import {MDXProvider} from "@mdx-js/react"; 10 | import PreviewComment from "./PreviewComment"; 11 | import {formatDistance} from 'date-fns'; 12 | import {Popover, PopoverContent, PopoverTrigger} from "./Popover"; 13 | import EmojiSelect from "./EmojiSelect"; 14 | import {DropdownMenu} from "./DropdownMenu"; 15 | import {EditingEditorComment} from "./EditingEditorComment"; 16 | 17 | interface CommentProps { 18 | className?: string; 19 | isMdxEditor?: boolean; 20 | formatDate?: string; 21 | value: Comment[]; 22 | currentUser: User, 23 | onChange?: (value: Comment[]) => void, 24 | theme: 'light' | 'dark' | 'system', 25 | allowUpVote?: boolean; 26 | onVoteChange?: (checked: boolean) => void 27 | } 28 | 29 | interface CommentCardProps { 30 | comment: Comment, 31 | onReply: (val: string) => void, 32 | currentUser: User, 33 | allowUpVote?: boolean; 34 | onChange: (change: any) => void; 35 | onDelete: () => void; 36 | onVoteChange: (change: boolean) => void; 37 | theme: 'light' | 'dark' | 'system', 38 | } 39 | 40 | export const CommentCard = ({ 41 | comment, 42 | onReply = () => { 43 | }, 44 | currentUser, 45 | allowUpVote, 46 | onChange, 47 | onVoteChange, 48 | theme, 49 | onDelete, 50 | }: CommentCardProps) => { 51 | const [replying, setReplying] = useState(false) 52 | const [editing, setEditing] = useState(false) 53 | 54 | const actions = ACTIONS.filter(e => comment.actions && comment.actions[e.id] && comment.selectedActions?.includes(e.id)) 55 | 56 | const upvote = (comment.actions ?? {})[ACTIONS_TYPE.UPVOTE]; 57 | 58 | const upvoted = comment.selectedActions?.includes(ACTIONS_TYPE.UPVOTE); 59 | 60 | return ( 61 |
62 |
63 | 64 | 65 | CN 66 | 67 |
68 |
69 |
71 |
72 | {comment.user?.fullName} 73 |
74 | { 78 | setEditing(true) 79 | }} 80 | deleteComment={onDelete} 81 | /> 82 |
83 |
84 | {editing ? 85 | { 90 | onChange({ 91 | text: val 92 | }) 93 | setEditing(false) 94 | }}/> 95 | : } 96 |
97 | {(allowUpVote && !editing) && 98 |
99 |
{ 101 | onVoteChange(!upvoted) 102 | const currentAmount = (comment.actions || {})[ACTIONS_TYPE.UPVOTE]; 103 | if (upvoted) { 104 | if (currentAmount) 105 | onChange({ 106 | selectedActions: comment.selectedActions?.filter(e => e !== ACTIONS_TYPE.UPVOTE), 107 | actions: { 108 | ...(comment.actions || {}), 109 | [ACTIONS_TYPE.UPVOTE]: currentAmount - 1, 110 | } 111 | }) 112 | } else { 113 | onChange({ 114 | selectedActions: [...(comment.selectedActions ?? []), ACTIONS_TYPE.UPVOTE], 115 | actions: { 116 | ...(comment.actions || {}), 117 | [ACTIONS_TYPE.UPVOTE]: currentAmount ? currentAmount + 1 : 1, 118 | } 119 | }) 120 | } 121 | }} 122 | className={`border ${upvoted ? `border-[#4493f8] text-[#4493f8]` : ''} rounded-xl px-2 py-0.5 inline-flex gap-1 items-center cursor-pointer`}> 123 | 124 | {upvote ?? 0} 125 |
126 |
127 | 128 | 129 |
130 | 131 |
132 |
133 | 134 | { 137 | const currentAmount = (comment.actions || {})[changeValue]; 138 | onChange({ 139 | selectedActions: v, 140 | actions: { 141 | ...(comment.actions || {}), 142 | [changeValue]: currentAmount ? currentAmount + 1 : 1, 143 | } 144 | }) 145 | }} 146 | onUnSelect={(v, changeValue: ACTIONS_TYPE) => { 147 | const currentAmount = (comment.actions || {})[changeValue]; 148 | if (currentAmount && currentAmount > 0) 149 | onChange({ 150 | selectedActions: v.filter(f => f !== changeValue), 151 | actions: { 152 | ...(comment.actions || {}), 153 | [changeValue]: currentAmount - 1, 154 | } 155 | }) 156 | }} 157 | className={''} 158 | /> 159 | 160 |
161 |
162 | {actions?.map(e => ( 163 |
167 | {e.emoji} 168 | {(comment.actions ?? {})[e.id]} 169 |
170 | ))} 171 |
} 172 |
173 |
174 | setReplying(true)}>Reply 175 | 176 | {formatDistance(Date.now(), comment.createdAt, {addSuffix: true})} 178 |
179 |
180 |
181 | {replying ? 182 |
183 | 184 |
185 | : null} 186 | {comment.replies && comment.replies.length > 0 ? 187 |
188 | {comment.replies.map(rep => ( 189 |
190 | 191 | 192 | CN 193 | 194 | 195 |
196 |
{rep.text}
197 |
198 |
{rep.user?.fullName}
199 |
{formatDistance(Date.now(), rep.createdAt, {addSuffix: true})}
201 |
202 |
203 |
204 | ))} 205 |
206 | : null} 207 |
208 | ) 209 | } 210 | 211 | export const CommentSection = ({ 212 | className = '', 213 | formatDate, 214 | isMdxEditor, 215 | value, 216 | onChange = () => { 217 | }, 218 | theme = 'light', 219 | currentUser, 220 | allowUpVote = false, 221 | onVoteChange = (change: boolean) => { 222 | } 223 | }: CommentProps) => { 224 | return ( 225 | ; 229 | }, 230 | }} 231 | > 232 |
233 | { 237 | onChange([{ 238 | id: makeid(8), 239 | user: currentUser, 240 | createdAt: new Date(), 241 | replies: [], 242 | text: val, 243 | }, ...(value ?? [])]) 244 | }}/> 245 | {value.map(e => ( 246 | { 249 | if (value) { 250 | onChange(value.map(f => f.id === e.id ? { 251 | ...f, 252 | replies: [{ 253 | id: makeid(8), 254 | parentId: e.id, 255 | user: currentUser, 256 | createdAt: new Date(), 257 | replies: [], 258 | text: rep, 259 | }, ...(f.replies ?? [])] 260 | } : f)) 261 | } 262 | }} 263 | onChange={(change: any) => { 264 | if (value) 265 | onChange(value.map(f => f.id === e.id ? { 266 | ...f, 267 | ...change, 268 | } : f)) 269 | }} 270 | onDelete={() => { 271 | onChange(value.filter(f => f.id !== e.id)) 272 | }} 273 | comment={e} 274 | key={e.id} 275 | allowUpVote={allowUpVote} 276 | theme={theme} 277 | onVoteChange={onVoteChange} 278 | /> 279 | ))} 280 |
281 |
282 | ) 283 | } -------------------------------------------------------------------------------- /src/mdx-style.css: -------------------------------------------------------------------------------- 1 | :root, .light, .light-theme { 2 | --blue-1: #fbfdff; 3 | --blue-2: #f4faff; 4 | --blue-3: #e6f4fe; 5 | --blue-4: #d5efff; 6 | --blue-5: #c2e5ff; 7 | --blue-6: #acd8fc; 8 | --blue-7: #8ec8f6; 9 | --blue-8: #5eb1ef; 10 | --blue-9: #0090ff; 11 | --blue-10: #0588f0; 12 | --blue-11: #0d74ce; 13 | --blue-12: #113264; 14 | } 15 | 16 | @supports (color: color(display-p3 1 1 1)) { 17 | @media (color-gamut: p3) { 18 | :root, .light, .light-theme { 19 | --blue-1: color(display-p3 0.986 0.992 0.999); 20 | --blue-2: color(display-p3 0.96 0.979 0.998); 21 | --blue-3: color(display-p3 0.912 0.956 0.991); 22 | --blue-4: color(display-p3 0.853 0.932 1); 23 | --blue-5: color(display-p3 0.788 0.894 0.998); 24 | --blue-6: color(display-p3 0.709 0.843 0.976); 25 | --blue-7: color(display-p3 0.606 0.777 0.947); 26 | --blue-8: color(display-p3 0.451 0.688 0.917); 27 | --blue-9: color(display-p3 0.247 0.556 0.969); 28 | --blue-10: color(display-p3 0.234 0.523 0.912); 29 | --blue-11: color(display-p3 0.15 0.44 0.84); 30 | --blue-12: color(display-p3 0.102 0.193 0.379); 31 | } 32 | } 33 | } 34 | 35 | .dark, .dark-theme { 36 | --blue-1: #0d1520; 37 | --blue-2: #111927; 38 | --blue-3: #0d2847; 39 | --blue-4: #003362; 40 | --blue-5: #004074; 41 | --blue-6: #104d87; 42 | --blue-7: #205d9e; 43 | --blue-8: #2870bd; 44 | --blue-9: #0090ff; 45 | --blue-10: #3b9eff; 46 | --blue-11: #70b8ff; 47 | --blue-12: #c2e6ff; 48 | } 49 | 50 | @supports (color: color(display-p3 1 1 1)) { 51 | @media (color-gamut: p3) { 52 | .dark, .dark-theme { 53 | --blue-1: color(display-p3 0.057 0.081 0.122); 54 | --blue-2: color(display-p3 0.072 0.098 0.147); 55 | --blue-3: color(display-p3 0.078 0.154 0.27); 56 | --blue-4: color(display-p3 0.033 0.197 0.37); 57 | --blue-5: color(display-p3 0.08 0.245 0.441); 58 | --blue-6: color(display-p3 0.14 0.298 0.511); 59 | --blue-7: color(display-p3 0.195 0.361 0.6); 60 | --blue-8: color(display-p3 0.239 0.434 0.72); 61 | --blue-9: color(display-p3 0.247 0.556 0.969); 62 | --blue-10: color(display-p3 0.344 0.612 0.973); 63 | --blue-11: color(display-p3 0.49 0.72 1); 64 | --blue-12: color(display-p3 0.788 0.898 0.99); 65 | } 66 | } 67 | } 68 | 69 | :root, .light, .light-theme { 70 | --slate-1: #fcfcfd; 71 | --slate-2: #f9f9fb; 72 | --slate-3: #f0f0f3; 73 | --slate-4: #e8e8ec; 74 | --slate-5: #e0e1e6; 75 | --slate-6: #d9d9e0; 76 | --slate-7: #cdced6; 77 | --slate-8: #b9bbc6; 78 | --slate-9: #8b8d98; 79 | --slate-10: #80838d; 80 | --slate-11: #60646c; 81 | --slate-12: #1c2024; 82 | --baseModalBg: white; 83 | } 84 | 85 | @supports (color: color(display-p3 1 1 1)) { 86 | @media (color-gamut: p3) { 87 | :root, .light, .light-theme { 88 | --slate-1: color(display-p3 0.988 0.988 0.992); 89 | --slate-2: color(display-p3 0.976 0.976 0.984); 90 | --slate-3: color(display-p3 0.94 0.941 0.953); 91 | --slate-4: color(display-p3 0.908 0.909 0.925); 92 | --slate-5: color(display-p3 0.88 0.881 0.901); 93 | --slate-6: color(display-p3 0.85 0.852 0.876); 94 | --slate-7: color(display-p3 0.805 0.808 0.838); 95 | --slate-8: color(display-p3 0.727 0.733 0.773); 96 | --slate-9: color(display-p3 0.547 0.553 0.592); 97 | --slate-10: color(display-p3 0.503 0.512 0.549); 98 | --slate-11: color(display-p3 0.379 0.392 0.421); 99 | --slate-12: color(display-p3 0.113 0.125 0.14); 100 | } 101 | } 102 | } 103 | 104 | .dark, .dark-theme { 105 | --slate-1: #111113; 106 | --slate-2: #18191b; 107 | --slate-3: #212225; 108 | --slate-4: #272a2d; 109 | --slate-5: #2e3135; 110 | --slate-6: #363a3f; 111 | --slate-7: #43484e; 112 | --slate-8: #5a6169; 113 | --slate-9: #696e77; 114 | --slate-10: #777b84; 115 | --slate-11: #b0b4ba; 116 | --slate-12: #edeef0; 117 | --baseModalBg: rgba(0,0,0,0.6); 118 | } 119 | 120 | @supports (color: color(display-p3 1 1 1)) { 121 | @media (color-gamut: p3) { 122 | .dark, .dark-theme { 123 | --slate-1: color(display-p3 0.067 0.067 0.074); 124 | --slate-2: color(display-p3 0.095 0.098 0.105); 125 | --slate-3: color(display-p3 0.13 0.135 0.145); 126 | --slate-4: color(display-p3 0.156 0.163 0.176); 127 | --slate-5: color(display-p3 0.183 0.191 0.206); 128 | --slate-6: color(display-p3 0.215 0.226 0.244); 129 | --slate-7: color(display-p3 0.265 0.28 0.302); 130 | --slate-8: color(display-p3 0.357 0.381 0.409); 131 | --slate-9: color(display-p3 0.415 0.431 0.463); 132 | --slate-10: color(display-p3 0.469 0.483 0.514); 133 | --slate-11: color(display-p3 0.692 0.704 0.728); 134 | --slate-12: color(display-p3 0.93 0.933 0.94); 135 | } 136 | } 137 | } 138 | 139 | :root, .light, .light-theme { 140 | --grass-1: #fbfefb; 141 | --grass-2: #f5fbf5; 142 | --grass-3: #e9f6e9; 143 | --grass-4: #daf1db; 144 | --grass-5: #c9e8ca; 145 | --grass-6: #b2ddb5; 146 | --grass-7: #94ce9a; 147 | --grass-8: #65ba74; 148 | --grass-9: #46a758; 149 | --grass-10: #3e9b4f; 150 | --grass-11: #2a7e3b; 151 | --grass-12: #203c25; 152 | } 153 | 154 | @supports (color: color(display-p3 1 1 1)) { 155 | @media (color-gamut: p3) { 156 | :root, .light, .light-theme { 157 | --grass-1: color(display-p3 0.986 0.996 0.985); 158 | --grass-2: color(display-p3 0.966 0.983 0.964); 159 | --grass-3: color(display-p3 0.923 0.965 0.917); 160 | --grass-4: color(display-p3 0.872 0.94 0.865); 161 | --grass-5: color(display-p3 0.811 0.908 0.802); 162 | --grass-6: color(display-p3 0.733 0.864 0.724); 163 | --grass-7: color(display-p3 0.628 0.803 0.622); 164 | --grass-8: color(display-p3 0.477 0.72 0.482); 165 | --grass-9: color(display-p3 0.38 0.647 0.378); 166 | --grass-10: color(display-p3 0.344 0.598 0.342); 167 | --grass-11: color(display-p3 0.263 0.488 0.261); 168 | --grass-12: color(display-p3 0.151 0.233 0.153); 169 | } 170 | } 171 | } 172 | 173 | :root, .light, .light-theme { 174 | --cyan-1: #fafdfe; 175 | --cyan-2: #f2fafb; 176 | --cyan-3: #def7f9; 177 | --cyan-4: #caf1f6; 178 | --cyan-5: #b5e9f0; 179 | --cyan-6: #9ddde7; 180 | --cyan-7: #7dcedc; 181 | --cyan-8: #3db9cf; 182 | --cyan-9: #00a2c7; 183 | --cyan-10: #0797b9; 184 | --cyan-11: #107d98; 185 | --cyan-12: #0d3c48; 186 | } 187 | 188 | @supports (color: color(display-p3 1 1 1)) { 189 | @media (color-gamut: p3) { 190 | :root, .light, .light-theme { 191 | --cyan-1: color(display-p3 0.982 0.992 0.996); 192 | --cyan-2: color(display-p3 0.955 0.981 0.984); 193 | --cyan-3: color(display-p3 0.888 0.965 0.975); 194 | --cyan-4: color(display-p3 0.821 0.941 0.959); 195 | --cyan-5: color(display-p3 0.751 0.907 0.935); 196 | --cyan-6: color(display-p3 0.671 0.862 0.9); 197 | --cyan-7: color(display-p3 0.564 0.8 0.854); 198 | --cyan-8: color(display-p3 0.388 0.715 0.798); 199 | --cyan-9: color(display-p3 0.282 0.627 0.765); 200 | --cyan-10: color(display-p3 0.264 0.583 0.71); 201 | --cyan-11: color(display-p3 0.08 0.48 0.63); 202 | --cyan-12: color(display-p3 0.108 0.232 0.277); 203 | } 204 | } 205 | } 206 | 207 | :root, .light, .light-theme { 208 | --amber-1: #fefdfb; 209 | --amber-2: #fefbe9; 210 | --amber-3: #fff7c2; 211 | --amber-4: #ffee9c; 212 | --amber-5: #fbe577; 213 | --amber-6: #f3d673; 214 | --amber-7: #e9c162; 215 | --amber-8: #e2a336; 216 | --amber-9: #ffc53d; 217 | --amber-10: #ffba18; 218 | --amber-11: #ab6400; 219 | --amber-12: #4f3422; 220 | } 221 | 222 | @supports (color: color(display-p3 1 1 1)) { 223 | @media (color-gamut: p3) { 224 | :root, .light, .light-theme { 225 | --amber-1: color(display-p3 0.995 0.992 0.985); 226 | --amber-2: color(display-p3 0.994 0.986 0.921); 227 | --amber-3: color(display-p3 0.994 0.969 0.782); 228 | --amber-4: color(display-p3 0.989 0.937 0.65); 229 | --amber-5: color(display-p3 0.97 0.902 0.527); 230 | --amber-6: color(display-p3 0.936 0.844 0.506); 231 | --amber-7: color(display-p3 0.89 0.762 0.443); 232 | --amber-8: color(display-p3 0.85 0.65 0.3); 233 | --amber-9: color(display-p3 1 0.77 0.26); 234 | --amber-10: color(display-p3 0.959 0.741 0.274); 235 | --amber-11: color(display-p3 0.64 0.4 0); 236 | --amber-12: color(display-p3 0.294 0.208 0.145); 237 | } 238 | } 239 | } 240 | 241 | :root, .light, .light-theme { 242 | --red-1: #fffcfc; 243 | --red-2: #fff7f7; 244 | --red-3: #feebec; 245 | --red-4: #ffdbdc; 246 | --red-5: #ffcdce; 247 | --red-6: #fdbdbe; 248 | --red-7: #f4a9aa; 249 | --red-8: #eb8e90; 250 | --red-9: #e5484d; 251 | --red-10: #dc3e42; 252 | --red-11: #ce2c31; 253 | --red-12: #641723; 254 | } 255 | 256 | @supports (color: color(display-p3 1 1 1)) { 257 | @media (color-gamut: p3) { 258 | :root, .light, .light-theme { 259 | --red-1: color(display-p3 0.998 0.989 0.988); 260 | --red-2: color(display-p3 0.995 0.971 0.971); 261 | --red-3: color(display-p3 0.985 0.925 0.925); 262 | --red-4: color(display-p3 0.999 0.866 0.866); 263 | --red-5: color(display-p3 0.984 0.812 0.811); 264 | --red-6: color(display-p3 0.955 0.751 0.749); 265 | --red-7: color(display-p3 0.915 0.675 0.672); 266 | --red-8: color(display-p3 0.872 0.575 0.572); 267 | --red-9: color(display-p3 0.83 0.329 0.324); 268 | --red-10: color(display-p3 0.798 0.294 0.285); 269 | --red-11: color(display-p3 0.744 0.234 0.222); 270 | --red-12: color(display-p3 0.36 0.115 0.143); 271 | } 272 | } 273 | } 274 | 275 | /** Code mirror */ 276 | 277 | .mdxeditor .cm-editor { 278 | --sp-font-mono: var(--font-mono); 279 | --sp-font-body: var(--font-body); 280 | padding: var(--sp-space-4) 0; 281 | } 282 | 283 | .mdxeditor .sp-editor .cm-editor { 284 | padding-bottom: 0; 285 | } 286 | 287 | .mdxeditor .cm-scroller { 288 | padding: 0 !important; 289 | } 290 | 291 | .mdxeditor .cm-focused { 292 | outline: none; 293 | } 294 | 295 | .mdxeditor .sp-wrapper { 296 | overflow: hidden; 297 | } 298 | 299 | .mdxeditor .sp-layout { 300 | border: none; 301 | } 302 | 303 | .mdxeditor .sp-cm pre { 304 | white-space: break-spaces; 305 | word-break: break-word; 306 | overflow-wrap: anywhere; 307 | flex-shrink: 1; 308 | } 309 | 310 | /** Diff viewer */ 311 | 312 | .mdxeditor .cm-mergeView .cm-scroller { 313 | font-family: var(--font-mono); 314 | line-height: 1.3rem; 315 | font-size: var(--text-xs); 316 | } 317 | 318 | /** Diff viewer */ 319 | 320 | .mdxeditor .cm-sourceView .cm-scroller { 321 | font-family: var(--font-mono); 322 | line-height: 1.3rem; 323 | font-size: var(--text-xs); 324 | } 325 | 326 | .mdxeditor .cm-gutters { 327 | background: transparent; 328 | font-size: var(--text-xxs); 329 | } 330 | 331 | .mdxeditor .cm-activeLine { 332 | background: transparent; 333 | } 334 | 335 | .mdxeditor .cm-tooltip-autocomplete { 336 | background: var(--baseBgSubtle); 337 | } 338 | 339 | .mdxeditor hr.selected[data-lexical-decorator=true] { 340 | outline: 2px solid highlight; 341 | } 342 | ._editorRoot_uazmk_53 { 343 | --accentBase: var(--blue-1); 344 | --accentBgSubtle: var(--blue-2); 345 | --accentBg: var(--blue-3); 346 | --accentBgHover: var(--blue-4); 347 | --accentBgActive: var(--blue-5); 348 | --accentLine: var(--blue-6); 349 | --accentBorder: var(--blue-7); 350 | --accentBorderHover: var(--blue-8); 351 | --accentSolid: var(--blue-9); 352 | --accentSolidHover: var(--blue-10); 353 | --accentText: var(--blue-11); 354 | --accentTextContrast: var(--blue-12); 355 | 356 | --basePageBg: white; 357 | --baseBase: var(--slate-1); 358 | --baseBgSubtle: var(--slate-2); 359 | --baseBg: var(--slate-3); 360 | --baseBgHover: var(--slate-4); 361 | --baseBgActive: var(--slate-5); 362 | --baseLine: var(--slate-6); 363 | --baseBorder: var(--slate-7); 364 | --baseBorderHover: var(--slate-8); 365 | --baseSolid: var(--slate-9); 366 | --baseSolidHover: var(--slate-10); 367 | --baseText: var(--slate-11); 368 | --baseTextContrast: var(--slate-12); 369 | 370 | --admonitionTipBg: var(--cyan-4); 371 | --admonitionTipBorder: var(--cyan-8); 372 | 373 | --admonitionInfoBg: var(--grass-4); 374 | --admonitionInfoBorder: var(--grass-8); 375 | 376 | --admonitionCautionBg: var(--amber-4); 377 | --admonitionCautionBorder: var(--amber-8); 378 | 379 | --admonitionDangerBg: var(--red-4); 380 | --admonitionDangerBorder: var(--red-8); 381 | 382 | --admonitionNoteBg: var(--slate-4); 383 | --admonitionNoteBorder: var(--slate-8); 384 | 385 | --error-color: var(--red-10); 386 | 387 | --spacing-0: 0px; 388 | --spacing-px: 1px; 389 | --spacing-0_5: 0.125rem; 390 | --spacing-1: 0.25rem; 391 | --spacing-1_5: 0.375rem; 392 | --spacing-2: 0.5rem; 393 | --spacing-2_5: 0.625rem; 394 | --spacing-3: 0.75rem; 395 | --spacing-3_5: 0.875rem; 396 | --spacing-4: 1rem; 397 | --spacing-5: 1.25rem; 398 | --spacing-6: 1.5rem; 399 | --spacing-7: 1.75rem; 400 | --spacing-8: 2rem; 401 | --spacing-9: 2.25rem; 402 | --spacing-10: 2.5rem; 403 | --spacing-11: 2.75rem; 404 | --spacing-12: 3rem; 405 | --spacing-14: 3.5rem; 406 | --spacing-16: 4rem; 407 | --spacing-20: 5rem; 408 | --spacing-24: 6rem; 409 | --spacing-28: 7rem; 410 | --spacing-32: 8rem; 411 | --spacing-36: 9rem; 412 | --spacing-40: 10rem; 413 | --spacing-44: 11rem; 414 | --spacing-48: 12rem; 415 | --spacing-52: 13rem; 416 | --spacing-56: 14rem; 417 | --spacing-60: 15rem; 418 | --spacing-64: 16rem; 419 | --spacing-72: 18rem; 420 | --spacing-80: 20rem; 421 | --spacing-96: 24rem; 422 | 423 | --radius-none: 0px; 424 | --radius-small: var(--spacing-0_5); 425 | --radius-base: var(--spacing-1); 426 | --radius-medium: var(--spacing-1_5); 427 | --radius-large: var(--spacing-2); 428 | --radius-extra-large: var(--spacing-3); 429 | --radius-full: 9999px; 430 | 431 | --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 432 | --font-body: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 433 | 434 | --text-base: 1rem; 435 | --text-sm: 0.875rem; 436 | --text-xs: 0.75rem; 437 | --text-xxs: 0.6rem; 438 | 439 | font-family: var(--font-body); 440 | color: var(--baseText); 441 | } 442 | 443 | ._editorWrapper_uazmk_154 {} 444 | 445 | ._nestedListItem_uazmk_156 { 446 | list-style: none; 447 | } 448 | 449 | ._toolbarRoot_uazmk_160 { 450 | z-index: 2; 451 | display: flex; 452 | flex-direction: row; 453 | gap: var(--spacing-1); 454 | border-top-left-radius: var(--radius-medium); 455 | border-top-right-radius: var(--radius-medium); 456 | padding: var(--spacing-1_5); 457 | align-items: center; 458 | overflow-x: auto; 459 | position: sticky; 460 | top: 0; 461 | background-color: var(--baseBg); 462 | width: inherit; 463 | } 464 | 465 | ._toolbarRoot_uazmk_160 div[role=separator] { 466 | margin: var(--spacing-2) var(--spacing-1); 467 | border-left: 1px solid var(--baseBorder); 468 | border-right: 1px solid var(--baseBase); 469 | height: var(--spacing-4); 470 | } 471 | 472 | ._toolbarRoot_uazmk_160 svg { 473 | color: var(--baseTextContrast); 474 | display: block; 475 | } 476 | 477 | ._readOnlyToolbarRoot_uazmk_187 { 478 | pointer-events: none; 479 | background: var(--baseBase); 480 | } 481 | 482 | ._readOnlyToolbarRoot_uazmk_187>div { 483 | opacity: 0.5; 484 | } 485 | 486 | ._toolbarModeSwitch_uazmk_196 { 487 | opacity: 1 !important; 488 | margin-left: auto; 489 | align-self: stretch; 490 | align-items: stretch; 491 | display: flex; 492 | border: 1px solid var(--baseBg); 493 | border-radius: var(--radius-medium); 494 | font-size: var(--text-xs); 495 | } 496 | 497 | ._toolbarModeSwitch_uazmk_196 ._toolbarToggleItem_uazmk_206 { 498 | padding-inline-end: var(--spacing-4); 499 | padding-inline-start: var(--spacing-4); 500 | } 501 | 502 | ._toolbarModeSwitch_uazmk_196 ._toolbarToggleItem_uazmk_206:active, 503 | ._toolbarModeSwitch_uazmk_196 ._toolbarToggleItem_uazmk_206[data-state=on] { 504 | background-color: var(--baseBorder); 505 | } 506 | 507 | ._toolbarGroupOfGroups_uazmk_217 { 508 | display: flex; 509 | margin: 0 var(--spacing-1); 510 | } 511 | 512 | ._toolbarToggleSingleGroup_uazmk_222:first-of-type ._toolbarToggleItem_uazmk_206:only-child, 513 | ._toolbarToggleSingleGroup_uazmk_222:only-child ._toolbarToggleItem_uazmk_206:first-child, 514 | ._toolbarModeSwitch_uazmk_196 ._toolbarToggleItem_uazmk_206:first-child { 515 | border-top-left-radius: var(--radius-base); 516 | border-bottom-left-radius: var(--radius-base); 517 | } 518 | 519 | ._toolbarToggleSingleGroup_uazmk_222:last-of-type ._toolbarToggleItem_uazmk_206:only-child, 520 | ._toolbarToggleSingleGroup_uazmk_222:only-child ._toolbarToggleItem_uazmk_206:last-child, 521 | ._toolbarModeSwitch_uazmk_196 ._toolbarToggleItem_uazmk_206:last-child { 522 | border-top-right-radius: var(--radius-base); 523 | border-bottom-right-radius: var(--radius-base); 524 | } 525 | 526 | ._toolbarToggleItem_uazmk_206, 527 | ._toolbarButton_uazmk_237 { 528 | border: 0; 529 | background-color: transparent; 530 | font-size: inherit; 531 | -webkit-appearance: none; 532 | -moz-appearance: none; 533 | appearance: none; 534 | all: unset; 535 | box-sizing: border-box; 536 | cursor: default; 537 | padding: var(--spacing-0_5); 538 | } 539 | 540 | @media (hover: hover) { 541 | ._toolbarToggleItem_uazmk_206:hover, ._toolbarButton_uazmk_237:hover { 542 | background-color: var(--baseBgActive); 543 | } 544 | } 545 | 546 | ._toolbarToggleItem_uazmk_206:active svg, ._toolbarButton_uazmk_237:active svg { 547 | transform: translate(1px, 1px); 548 | } 549 | 550 | ._toolbarToggleItem_uazmk_206[data-state=on], 551 | ._toolbarButton_uazmk_237[data-state=on], 552 | ._toolbarToggleItem_uazmk_206:active, 553 | ._toolbarButton_uazmk_237:active { 554 | color: var(--baseTextContrast); 555 | background-color: var(--baseBgActive); 556 | } 557 | 558 | ._toolbarToggleItem_uazmk_206[data-disabled], ._toolbarButton_uazmk_237[data-disabled] { 559 | pointer-events: none; 560 | } 561 | 562 | ._toolbarToggleItem_uazmk_206[data-disabled] svg, ._toolbarButton_uazmk_237[data-disabled] svg { 563 | color: var(--baseBorderHover); 564 | } 565 | 566 | ._toolbarButton_uazmk_237 { 567 | border-radius: var(--radius-base); 568 | } 569 | 570 | ._toolbarButton_uazmk_237 + ._toolbarButton_uazmk_237 { 571 | margin-left: var(--spacing-1); 572 | } 573 | 574 | ._activeToolbarButton_uazmk_274 { 575 | color: var(--accentText); 576 | } 577 | 578 | ._toolbarToggleSingleGroup_uazmk_222 { 579 | display: flex; 580 | align-items: center; 581 | white-space: nowrap; 582 | } 583 | 584 | ._toolbarNodeKindSelectContainer_uazmk_284, 585 | ._toolbarButtonDropdownContainer_uazmk_285, 586 | ._toolbarCodeBlockLanguageSelectContent_uazmk_286, 587 | ._selectContainer_uazmk_287 { 588 | filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.20)); 589 | z-index: 3; 590 | width: var(--spacing-36); 591 | border-bottom-left-radius: var(--radius-base); 592 | border-bottom-right-radius: var(--radius-base); 593 | background-color: var(--basePageBg); 594 | font-size: var(--text-sm); 595 | } 596 | 597 | ._toolbarButtonDropdownContainer_uazmk_285 { 598 | border-top-right-radius: var(--radius-base); 599 | } 600 | 601 | ._toolbarButtonDropdownContainer_uazmk_285 ._selectItem_uazmk_300:first-child { 602 | border-top-right-radius: var(--radius-base); 603 | } 604 | 605 | ._toolbarNodeKindSelectTrigger_uazmk_305, 606 | ._toolbarButtonSelectTrigger_uazmk_306, 607 | ._selectTrigger_uazmk_307 { 608 | border: 0; 609 | background-color: transparent; 610 | display: flex; 611 | color: inherit; 612 | align-items: center; 613 | width: var(--spacing-36); 614 | padding: var(--spacing-0_5) var(--spacing-1); 615 | padding-inline-start: var(--spacing-2); 616 | border-radius: var(--radius-medium); 617 | white-space: nowrap; 618 | flex-wrap: nowrap; 619 | font-size: var(--text-sm); 620 | background-color: var(--basePageBg); 621 | margin: 0 var(--spacing-1); 622 | } 623 | 624 | ._toolbarNodeKindSelectTrigger_uazmk_305[data-state=open], ._toolbarButtonSelectTrigger_uazmk_306[data-state=open], ._selectTrigger_uazmk_307[data-state=open] { 625 | filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.20)); 626 | border-bottom-right-radius: var(--radius-none); 627 | border-bottom-left-radius: var(--radius-none); 628 | } 629 | 630 | ._selectTrigger_uazmk_307[data-placeholder]>span:first-child { 631 | color: var(--baseBorderHover); 632 | } 633 | 634 | /** used in the sandpack */ 635 | ._toolbarButtonSelectTrigger_uazmk_306 { 636 | width: auto; 637 | padding-inline-start: var(--spacing-2); 638 | padding-inline-end: var(--spacing-1); 639 | padding-block: var(--spacing-0_5); 640 | } 641 | 642 | ._toolbarCodeBlockLanguageSelectTrigger_uazmk_342, 643 | ._toolbarCodeBlockLanguageSelectContent_uazmk_286 { 644 | width: var(--spacing-48); 645 | } 646 | 647 | ._toolbarNodeKindSelectItem_uazmk_347, 648 | ._selectItem_uazmk_300 { 649 | cursor: default; 650 | display: flex; 651 | padding: var(--spacing-2); 652 | } 653 | 654 | ._toolbarNodeKindSelectItem_uazmk_347[data-highlighted], ._selectItem_uazmk_300[data-highlighted] { 655 | background-color: var(--baseBg); 656 | } 657 | 658 | ._toolbarNodeKindSelectItem_uazmk_347[data-state=checked], ._selectItem_uazmk_300[data-state=checked] { 659 | color: var(--baseTextContrast); 660 | background-color: var(--baseBg); 661 | } 662 | 663 | ._toolbarNodeKindSelectItem_uazmk_347[data-highlighted], ._selectItem_uazmk_300[data-highlighted] { 664 | outline: none; 665 | } 666 | 667 | ._toolbarNodeKindSelectItem_uazmk_347:last-child, ._selectItem_uazmk_300:last-child { 668 | border-bottom-left-radius: var(--radius-base); 669 | border-bottom-right-radius: var(--radius-base); 670 | } 671 | 672 | ._toolbarNodeKindSelectDropdownArrow_uazmk_372, 673 | ._selectDropdownArrow_uazmk_373 { 674 | margin-left: auto; 675 | display: flex; 676 | align-items: center; 677 | } 678 | 679 | ._contentEditable_uazmk_379 { 680 | box-sizing: border-box; 681 | width: 100%; 682 | color: var(--baseTextContrast); 683 | 684 | padding: var(--spacing-3); 685 | } 686 | 687 | ._contentEditable_uazmk_379:focus { 688 | outline: none; 689 | } 690 | 691 | ._codeMirrorWrapper_uazmk_391 { 692 | margin-bottom: var(--spacing-5); 693 | border: 1px solid var(--baseLine); 694 | border-radius: var(--radius-medium); 695 | overflow: hidden; 696 | padding: 0.8rem; 697 | position: relative; 698 | } 699 | 700 | ._sandPackWrapper_uazmk_400 { 701 | margin-bottom: var(--spacing-5); 702 | border: 1px solid var(--baseLine); 703 | border-radius: var(--radius-medium); 704 | overflow: hidden; 705 | position: relative; 706 | } 707 | 708 | ._codeMirrorToolbar_uazmk_408 { 709 | position: absolute; 710 | right: 0; 711 | top: 0; 712 | display: flex; 713 | gap: var(--spacing-1); 714 | padding: var(--spacing-1); 715 | z-index: 1; 716 | background-color: var(--baseBase); 717 | border-bottom-left-radius: var(--radius-base); 718 | } 719 | 720 | ._frontmatterWrapper_uazmk_412 { 721 | border-radius: var(--radius-medium); 722 | padding: var(--spacing-3); 723 | background-color: var(--baseBgSubtle); 724 | } 725 | 726 | ._frontmatterWrapper_uazmk_412[data-expanded=true] { 727 | margin-bottom: var(--spacing-10); 728 | } 729 | 730 | ._frontmatterToggleButton_uazmk_422 { 731 | border: 0; 732 | background-color: transparent; 733 | font-size: inherit; 734 | -webkit-appearance: none; 735 | -moz-appearance: none; 736 | appearance: none; 737 | all: unset; 738 | box-sizing: border-box; 739 | cursor: default; 740 | display: flex; 741 | align-items: center; 742 | gap: var(--spacing-1); 743 | font-size: var(--text-sm); 744 | } 745 | 746 | ._propertyPanelTitle_uazmk_430 { 747 | font-size: var(--text-xs); 748 | font-weight: 400; 749 | margin: 0; 750 | padding-top: var(--spacing-2); 751 | padding-left: var(--spacing-2); 752 | } 753 | 754 | ._propertyEditorTable_uazmk_438 { 755 | table-layout: fixed; 756 | border-spacing: var(--spacing-2); 757 | } 758 | 759 | ._propertyEditorTable_uazmk_438 th { 760 | text-align: left; 761 | font-size: var(--text-sm); 762 | padding: var(--spacing-2) var(--spacing-3); 763 | } 764 | 765 | ._propertyEditorTable_uazmk_438 col:nth-child(1) { 766 | width: 30%; 767 | } 768 | 769 | ._propertyEditorTable_uazmk_438 col:nth-child(2) { 770 | width: 70%; 771 | } 772 | 773 | ._propertyEditorTable_uazmk_438 td:last-child ._iconButton_uazmk_456 { 774 | margin-left: var(--spacing-4); 775 | margin-right: var(--spacing-4); 776 | } 777 | 778 | ._propertyEditorTable_uazmk_438 ._readOnlyColumnCell_uazmk_461 { 779 | padding-left: 0; 780 | } 781 | 782 | ._propertyEditorLabelCell_uazmk_466 { 783 | font-weight: 400; 784 | } 785 | 786 | ._readOnlyColumnCell_uazmk_461 { 787 | padding-left: 0; 788 | } 789 | 790 | ._buttonsFooter_uazmk_474 { 791 | display: flex; 792 | justify-content: flex-end; 793 | gap: var(--spacing-2); 794 | } 795 | 796 | ._propertyEditorInput_uazmk_480 { 797 | border: 0; 798 | background-color: transparent; 799 | font-size: inherit; 800 | -webkit-appearance: none; 801 | -moz-appearance: none; 802 | appearance: none; 803 | all: unset; 804 | box-sizing: border-box; 805 | cursor: default; 806 | width: 100%; 807 | padding: var(--spacing-2) var(--spacing-3); 808 | border-radius: var(--radius-base); 809 | border: 1px solid var(--baseBorder); 810 | background-color: var(--baseBase); 811 | font-size: var(--text-sm); 812 | } 813 | 814 | ._iconButton_uazmk_456 { 815 | border: 0; 816 | background-color: transparent; 817 | font-size: inherit; 818 | -webkit-appearance: none; 819 | -moz-appearance: none; 820 | appearance: none; 821 | all: unset; 822 | box-sizing: border-box; 823 | cursor: default; 824 | color: var(--baseText); 825 | } 826 | 827 | @media (hover: hover) { 828 | ._iconButton_uazmk_456:hover { 829 | color: var(--baseTextContrast); 830 | } 831 | } 832 | 833 | ._iconButton_uazmk_456:disabled, 834 | ._iconButton_uazmk_456:disabled:hover { 835 | color: var(--baseLine); 836 | } 837 | 838 | ._primaryButton_uazmk_506, 839 | ._secondaryButton_uazmk_507 { 840 | border: 0; 841 | background-color: transparent; 842 | font-size: inherit; 843 | -webkit-appearance: none; 844 | -moz-appearance: none; 845 | appearance: none; 846 | all: unset; 847 | box-sizing: border-box; 848 | cursor: default; 849 | padding: var(--spacing-2) var(--spacing-3); 850 | border: 1px solid var(--accentBorder); 851 | background-color: var(--accentSolidHover); 852 | color: var(--baseBase); 853 | font-size: var(--text-xs); 854 | border-radius: var(--radius-medium); 855 | } 856 | 857 | ._primaryButton_uazmk_506:disabled, ._secondaryButton_uazmk_507:disabled { 858 | background: var(--accentLine); 859 | border-color: var(--accentBg); 860 | } 861 | 862 | ._smallButton_uazmk_522 { 863 | font-size: var(--text-xs); 864 | padding: var(--spacing-1) var(--spacing-2); 865 | border-radius: var(--radius-base); 866 | } 867 | 868 | ._secondaryButton_uazmk_507 { 869 | border: 1px solid var(--baseBorder); 870 | background-color: var(--baseSolidHover); 871 | color: var(--baseBase); 872 | } 873 | 874 | ._dialogForm_uazmk_534 { 875 | display: flex; 876 | flex-direction: row; 877 | gap: var(--spacing-2); 878 | } 879 | 880 | ._linkDialogEditForm_uazmk_540 { 881 | display: flex; 882 | flex-direction: column; 883 | align-items: stretch; 884 | gap: var(--spacing-2); 885 | padding: 0; 886 | } 887 | 888 | ._linkDialogInputContainer_uazmk_548 { 889 | display: flex; 890 | flex-direction: column; 891 | align-items: stretch; 892 | } 893 | 894 | ._linkDialogInputWrapper_uazmk_554 { 895 | display: flex; 896 | align-items: center; 897 | background-color: var(--baseBase); 898 | 899 | border-radius: var(--radius-base); 900 | border: 1px solid var(--baseBorder); 901 | } 902 | 903 | ._linkDialogInputWrapper_uazmk_554[data-visible-dropdown=true] { 904 | border-bottom-left-radius: var(--radius-none); 905 | border-bottom-right-radius: var(--radius-none); 906 | border-bottom-width: 0; 907 | } 908 | 909 | ._linkDialogInputWrapper_uazmk_554>button { 910 | border: 0; 911 | background-color: transparent; 912 | font-size: inherit; 913 | -webkit-appearance: none; 914 | -moz-appearance: none; 915 | appearance: none; 916 | all: unset; 917 | box-sizing: border-box; 918 | cursor: default; 919 | padding-right: var(--spacing-2); 920 | } 921 | 922 | ._linkDialogInput_uazmk_548, 923 | ._dialogInput_uazmk_575 { 924 | border: 0; 925 | background-color: transparent; 926 | font-size: inherit; 927 | -webkit-appearance: none; 928 | -moz-appearance: none; 929 | appearance: none; 930 | all: unset; 931 | box-sizing: border-box; 932 | cursor: default; 933 | width: 20rem; 934 | padding: var(--spacing-2) var(--spacing-3); 935 | font-size: var(--text-sm); 936 | } 937 | 938 | ._linkDialogInput_uazmk_548::-moz-placeholder, ._dialogInput_uazmk_575::-moz-placeholder { 939 | color: var(--baseBorder); 940 | } 941 | 942 | ._linkDialogInput_uazmk_548::placeholder, ._dialogInput_uazmk_575::placeholder { 943 | color: var(--baseBorder); 944 | } 945 | 946 | ._linkDialogAnchor_uazmk_586 { 947 | position: fixed; 948 | background-color: highlight; 949 | z-index: -1; 950 | } 951 | 952 | ._linkDialogAnchor_uazmk_586[data-visible=true] { 953 | visibility: visible; 954 | } 955 | 956 | ._linkDialogAnchor_uazmk_586[data-visible=false] { 957 | visibility: hidden; 958 | } 959 | 960 | ._linkDialogPopoverContent_uazmk_600, 961 | ._tableColumnEditorPopoverContent_uazmk_601, 962 | ._dialogContent_uazmk_602 { 963 | filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.20)); 964 | display: flex; 965 | align-items: center; 966 | gap: var(--spacing-0_5); 967 | border-radius: var(--radius-medium); 968 | border: 1px solid var(--baseBg); 969 | background-color: var(--baseModalBg); 970 | padding: var(--spacing-1) var(--spacing-1); 971 | font-size: var(--text-sm); 972 | } 973 | 974 | ._largeDialogContent_uazmk_614 { 975 | filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.20)); 976 | gap: var(--spacing-0_5); 977 | border-radius: var(--radius-medium); 978 | border: 1px solid var(--baseBorder); 979 | background-color: var(--baseBgSubtle); 980 | padding: var(--spacing-4); 981 | font-size: var(--text-sm); 982 | } 983 | 984 | ._dialogTitle_uazmk_624 { 985 | font-size: var(--text-base); 986 | font-weight: 600; 987 | padding-left: var(--spacing-2); 988 | } 989 | 990 | ._dialogCloseButton_uazmk_630 { 991 | border: 0; 992 | background-color: transparent; 993 | font-size: inherit; 994 | -webkit-appearance: none; 995 | -moz-appearance: none; 996 | appearance: none; 997 | all: unset; 998 | box-sizing: border-box; 999 | cursor: default; 1000 | position: absolute; 1001 | top: 10px; 1002 | right: 10px; 1003 | } 1004 | 1005 | ._popoverContent_uazmk_637 { 1006 | filter: drop-shadow(0 2px 2px rgb(0 0 0 / 0.20)); 1007 | display: flex; 1008 | align-items: center; 1009 | gap: var(--spacing-0_5); 1010 | border-radius: var(--radius-medium); 1011 | background-color: var(--baseBgSubtle); 1012 | padding: var(--spacing-2) var(--spacing-2); 1013 | font-size: var(--text-sm); 1014 | z-index: 1; 1015 | } 1016 | 1017 | ._popoverArrow_uazmk_649 { 1018 | fill: var(--basePageBg); 1019 | } 1020 | 1021 | ._linkDialogPreviewAnchor_uazmk_653 { 1022 | margin-right: var(--spacing-1); 1023 | display: flex; 1024 | align-items: center; 1025 | color: var(--accentText); 1026 | text-decoration: none; 1027 | 1028 | border: 1px solid transparent; 1029 | } 1030 | 1031 | @media (hover: hover) { 1032 | ._linkDialogPreviewAnchor_uazmk_653:hover { 1033 | color: var(--accentSolidHover); 1034 | } 1035 | } 1036 | 1037 | ._linkDialogPreviewAnchor_uazmk_653 span { 1038 | max-width: 14rem; 1039 | overflow-x: hidden; 1040 | text-overflow: ellipsis; 1041 | white-space: nowrap; 1042 | } 1043 | 1044 | ._tooltipTrigger_uazmk_676 { 1045 | align-self: center; 1046 | } 1047 | 1048 | ._tooltipContent_uazmk_680 { 1049 | z-index: 2; 1050 | position: relative; 1051 | border-radius: var(--radius-medium); 1052 | padding: var(--spacing-1) var(--spacing-2); 1053 | font-size: var(--text-xs); 1054 | background-color: var(--baseText); 1055 | color: var(--baseBase); 1056 | } 1057 | 1058 | ._tooltipContent_uazmk_680 svg { 1059 | fill: var(--baseText); 1060 | } 1061 | 1062 | ._actionButton_uazmk_694 { 1063 | border: 0; 1064 | background-color: transparent; 1065 | font-size: inherit; 1066 | -webkit-appearance: none; 1067 | -moz-appearance: none; 1068 | appearance: none; 1069 | all: unset; 1070 | box-sizing: border-box; 1071 | cursor: default; 1072 | padding: var(--spacing-1); 1073 | color: var(--baseTextContrast); 1074 | padding: var(--spacing-1) var(--spacing-1); 1075 | border-radius: var(--radius-medium); 1076 | color: var(--baseTextContrast); 1077 | } 1078 | 1079 | ._actionButton_uazmk_694 svg { 1080 | display: block; 1081 | } 1082 | 1083 | @media (hover: hover) { 1084 | ._actionButton_uazmk_694:hover { 1085 | background-color: var(--baseBg); 1086 | } 1087 | } 1088 | 1089 | ._actionButton_uazmk_694:active svg { 1090 | transform: translate(1px, 1px); 1091 | } 1092 | 1093 | ._actionButton_uazmk_694[data-state=on], 1094 | ._actionButton_uazmk_694:active { 1095 | background-color: var(--baseBg); 1096 | color: var(--baseTextContrast); 1097 | } 1098 | 1099 | ._primaryActionButton_uazmk_701 { 1100 | background-color: var(--accentSolid); 1101 | color: var(--baseBase); 1102 | } 1103 | 1104 | @media (hover: hover) { 1105 | ._primaryActionButton_uazmk_701:hover { 1106 | background-color: var(--accentSolidHover); 1107 | color: var(--baseBase); 1108 | } 1109 | } 1110 | 1111 | ._tableEditor_uazmk_713 { 1112 | table-layout: fixed; 1113 | width: 100%; 1114 | height: 100%; 1115 | border-spacing: 0; 1116 | border-collapse: collapse; 1117 | } 1118 | 1119 | ._tableEditor_uazmk_713 thead>tr>th { 1120 | text-align: right; 1121 | } 1122 | 1123 | ._tableEditor_uazmk_713>tbody>tr>td:not(._toolCell_uazmk_724), 1124 | ._tableEditor_uazmk_713>tbody>tr>th:not(._toolCell_uazmk_724):not([data-tool-cell="true"]) { 1125 | border: 1px solid var(--baseBgActive); 1126 | padding: var(--spacing-1) var(--spacing-2); 1127 | white-space: normal; 1128 | } 1129 | 1130 | :is(._tableEditor_uazmk_713>tbody>tr>td:not(._toolCell_uazmk_724),._tableEditor_uazmk_713>tbody>tr>th:not(._toolCell_uazmk_724):not([data-tool-cell="true"]))>div { 1131 | outline: none; 1132 | } 1133 | 1134 | :is(._tableEditor_uazmk_713>tbody>tr>td:not(._toolCell_uazmk_724),._tableEditor_uazmk_713>tbody>tr>th:not(._toolCell_uazmk_724):not([data-tool-cell="true"]))>div>p { 1135 | margin: 0; 1136 | } 1137 | 1138 | [data-active=true]:is(._tableEditor_uazmk_713>tbody>tr>td:not(._toolCell_uazmk_724),._tableEditor_uazmk_713>tbody>tr>th:not(._toolCell_uazmk_724):not([data-tool-cell="true"])) { 1139 | outline: solid 1px var(--baseSolid); 1140 | } 1141 | 1142 | ._tableEditor_uazmk_713 ._tableColumnEditorTrigger_uazmk_743, 1143 | ._tableEditor_uazmk_713 ._tableRowEditorTrigger_uazmk_744, 1144 | ._tableEditor_uazmk_713 ._addRowButton_uazmk_745, 1145 | ._tableEditor_uazmk_713 ._addColumnButton_uazmk_746, 1146 | ._tableEditor_uazmk_713 ._iconButton_uazmk_456 { 1147 | opacity: .15; 1148 | } 1149 | 1150 | @media (hover: hover) { 1151 | 1152 | ._tableEditor_uazmk_713:hover ._tableColumnEditorTrigger_uazmk_743, 1153 | ._tableEditor_uazmk_713:hover ._tableRowEditorTrigger_uazmk_744, 1154 | ._tableEditor_uazmk_713:hover ._addRowButton_uazmk_745, 1155 | ._tableEditor_uazmk_713:hover ._addColumnButton_uazmk_746, 1156 | ._tableEditor_uazmk_713:hover ._iconButton_uazmk_456 { 1157 | opacity: 0.3; 1158 | } 1159 | 1160 | ._tableEditor_uazmk_713:hover ._tableColumnEditorTrigger_uazmk_743:hover, ._tableEditor_uazmk_713:hover ._tableRowEditorTrigger_uazmk_744:hover, ._tableEditor_uazmk_713:hover ._addRowButton_uazmk_745:hover, ._tableEditor_uazmk_713:hover ._addColumnButton_uazmk_746:hover, ._tableEditor_uazmk_713:hover ._iconButton_uazmk_456:hover { 1161 | opacity: 1; 1162 | } 1163 | } 1164 | 1165 | ._toolCell_uazmk_724 { 1166 | text-align: right; 1167 | } 1168 | 1169 | ._toolCell_uazmk_724 button { 1170 | margin: auto; 1171 | display: block; 1172 | } 1173 | 1174 | ._tableColumnEditorTrigger_uazmk_743 { 1175 | border: 0; 1176 | background-color: transparent; 1177 | font-size: inherit; 1178 | -webkit-appearance: none; 1179 | -moz-appearance: none; 1180 | appearance: none; 1181 | all: unset; 1182 | box-sizing: border-box; 1183 | cursor: default; 1184 | padding: var(--spacing-1); 1185 | color: var(--baseTextContrast); 1186 | padding: var(--spacing-1); 1187 | border-radius: var(--radius-full); 1188 | opacity: 0.2; 1189 | } 1190 | 1191 | ._tableColumnEditorTrigger_uazmk_743 svg { 1192 | display: block; 1193 | } 1194 | 1195 | @media (hover: hover) { 1196 | ._tableColumnEditorTrigger_uazmk_743:hover { 1197 | background-color: var(--baseBg); 1198 | } 1199 | } 1200 | 1201 | ._tableColumnEditorTrigger_uazmk_743:active svg { 1202 | transform: translate(1px, 1px); 1203 | } 1204 | 1205 | ._tableColumnEditorTrigger_uazmk_743[data-state=on], 1206 | ._tableColumnEditorTrigger_uazmk_743:active { 1207 | background-color: var(--baseBg); 1208 | color: var(--baseTextContrast); 1209 | } 1210 | 1211 | ._tableColumnEditorTrigger_uazmk_743[data-active=true] { 1212 | opacity: 1 !important; 1213 | } 1214 | 1215 | ._tableColumnEditorToolbar_uazmk_789 { 1216 | display: flex; 1217 | } 1218 | 1219 | ._tableColumnEditorToolbar_uazmk_789>button { 1220 | border: 0; 1221 | background-color: transparent; 1222 | font-size: inherit; 1223 | -webkit-appearance: none; 1224 | -moz-appearance: none; 1225 | appearance: none; 1226 | all: unset; 1227 | box-sizing: border-box; 1228 | cursor: default; 1229 | padding: var(--spacing-1); 1230 | color: var(--baseTextContrast); 1231 | } 1232 | 1233 | ._tableColumnEditorToolbar_uazmk_789>button svg { 1234 | display: block; 1235 | } 1236 | 1237 | @media (hover: hover) { 1238 | ._tableColumnEditorToolbar_uazmk_789>button:hover { 1239 | background-color: var(--baseBg); 1240 | } 1241 | } 1242 | 1243 | ._tableColumnEditorToolbar_uazmk_789>button:active svg { 1244 | transform: translate(1px, 1px); 1245 | } 1246 | 1247 | ._tableColumnEditorToolbar_uazmk_789>button[data-state=on], 1248 | ._tableColumnEditorToolbar_uazmk_789>button:active { 1249 | background-color: var(--baseBg); 1250 | color: var(--baseTextContrast); 1251 | } 1252 | 1253 | ._tableColumnEditorToolbar_uazmk_789 [role=separator] { 1254 | margin-left: var(--spacing-1); 1255 | margin-right: var(--spacing-1); 1256 | } 1257 | 1258 | 1259 | ._toggleGroupRoot_uazmk_803 { 1260 | display: inline-flex; 1261 | } 1262 | 1263 | 1264 | ._toggleGroupRoot_uazmk_803 button { 1265 | border: 0; 1266 | background-color: transparent; 1267 | font-size: inherit; 1268 | -webkit-appearance: none; 1269 | -moz-appearance: none; 1270 | appearance: none; 1271 | all: unset; 1272 | box-sizing: border-box; 1273 | cursor: default; 1274 | padding: var(--spacing-1); 1275 | color: var(--baseTextContrast); 1276 | } 1277 | 1278 | 1279 | ._toggleGroupRoot_uazmk_803 button svg { 1280 | display: block; 1281 | } 1282 | 1283 | 1284 | @media (hover: hover) { 1285 | ._toggleGroupRoot_uazmk_803 button:hover { 1286 | background-color: var(--baseBg); 1287 | } 1288 | } 1289 | 1290 | 1291 | ._toggleGroupRoot_uazmk_803 button:active svg { 1292 | transform: translate(1px, 1px); 1293 | } 1294 | 1295 | 1296 | ._toggleGroupRoot_uazmk_803 button[data-state=on], 1297 | ._toggleGroupRoot_uazmk_803 button:active { 1298 | background-color: var(--baseBg); 1299 | color: var(--baseTextContrast); 1300 | } 1301 | 1302 | 1303 | ._toggleGroupRoot_uazmk_803 button:first-child { 1304 | border-top-left-radius: var(--radius-base); 1305 | border-bottom-left-radius: var(--radius-base); 1306 | } 1307 | 1308 | 1309 | ._toggleGroupRoot_uazmk_803 button:last-child { 1310 | border-top-right-radius: var(--radius-base); 1311 | border-bottom-right-radius: var(--radius-base); 1312 | } 1313 | 1314 | ._tableToolsColumn_uazmk_821 { 1315 | width: 2rem; 1316 | } 1317 | 1318 | ._tableToolsColumn_uazmk_821 button { 1319 | margin: auto; 1320 | display: block; 1321 | } 1322 | 1323 | ._leftAlignedCell_uazmk_830 { 1324 | text-align: left; 1325 | } 1326 | 1327 | ._rightAlignedCell_uazmk_834 { 1328 | text-align: right; 1329 | } 1330 | 1331 | ._centeredCell_uazmk_838 { 1332 | text-align: center; 1333 | } 1334 | 1335 | ._addColumnButton_uazmk_746, 1336 | ._addRowButton_uazmk_745 { 1337 | border: 0; 1338 | background-color: transparent; 1339 | font-size: inherit; 1340 | -webkit-appearance: none; 1341 | -moz-appearance: none; 1342 | appearance: none; 1343 | all: unset; 1344 | box-sizing: border-box; 1345 | cursor: default; 1346 | padding: var(--spacing-1); 1347 | color: var(--baseTextContrast); 1348 | background-color: var(--baseBase); 1349 | 1350 | display: flex; 1351 | align-items: center; 1352 | } 1353 | 1354 | ._addColumnButton_uazmk_746 svg, ._addRowButton_uazmk_745 svg { 1355 | display: block; 1356 | } 1357 | 1358 | @media (hover: hover) { 1359 | ._addColumnButton_uazmk_746:hover, ._addRowButton_uazmk_745:hover { 1360 | background-color: var(--baseBg); 1361 | } 1362 | } 1363 | 1364 | ._addColumnButton_uazmk_746:active svg, ._addRowButton_uazmk_745:active svg { 1365 | transform: translate(1px, 1px); 1366 | } 1367 | 1368 | ._addColumnButton_uazmk_746[data-state=on], 1369 | ._addRowButton_uazmk_745[data-state=on], 1370 | ._addColumnButton_uazmk_746:active, 1371 | ._addRowButton_uazmk_745:active { 1372 | background-color: var(--baseBg); 1373 | color: var(--baseTextContrast); 1374 | } 1375 | 1376 | ._addColumnButton_uazmk_746 svg, ._addRowButton_uazmk_745 svg { 1377 | margin: auto; 1378 | } 1379 | 1380 | ._addRowButton_uazmk_745 { 1381 | width: 100%; 1382 | margin-top: var(--spacing-px); 1383 | box-sizing: border-box; 1384 | border-bottom-right-radius: var(--radius-medium); 1385 | border-bottom-left-radius: var(--radius-medium); 1386 | } 1387 | 1388 | ._addColumnButton_uazmk_746 { 1389 | margin-left: var(--spacing-px); 1390 | height: 100%; 1391 | border-top-right-radius: var(--radius-medium); 1392 | border-bottom-right-radius: var(--radius-medium); 1393 | } 1394 | 1395 | /** Dialog */ 1396 | ._dialogOverlay_uazmk_871 { 1397 | position: fixed; 1398 | inset: 0; 1399 | animation: _overlayShow_uazmk_1 150ms cubic-bezier(0.16, 1, 0.3, 1); 1400 | background-color: var(--baseBase); 1401 | z-index: 51; 1402 | opacity: 0.5; 1403 | } 1404 | 1405 | ._dialogContent_uazmk_602, 1406 | ._largeDialogContent_uazmk_614 { 1407 | position: fixed; 1408 | top: 50%; 1409 | left: 50%; 1410 | transform: translate(-50%, -50%); 1411 | animation: _contentShow_uazmk_1 150ms cubic-bezier(0.16, 1, 0.3, 1); 1412 | z-index: 52; 1413 | } 1414 | 1415 | ._dialogContent_uazmk_602:focus, 1416 | ._largeDialogContent_uazmk_614:focus { 1417 | outline: none; 1418 | } 1419 | 1420 | 1421 | @keyframes _overlayShow_uazmk_1 { 1422 | from { 1423 | opacity: 0; 1424 | } 1425 | 1426 | to { 1427 | opacity: .5; 1428 | } 1429 | } 1430 | 1431 | @keyframes _contentShow_uazmk_1 { 1432 | from { 1433 | opacity: 0; 1434 | transform: translate(-50%, -48%) scale(0.96); 1435 | } 1436 | 1437 | to { 1438 | opacity: 1; 1439 | transform: translate(-50%, -50%) scale(1); 1440 | } 1441 | } 1442 | 1443 | ._focusedImage_uazmk_918 { 1444 | outline: highlight solid 2px; 1445 | } 1446 | 1447 | ._imageWrapper_uazmk_922 { 1448 | display: inline-block; 1449 | position: relative; 1450 | } 1451 | 1452 | ._imageWrapper_uazmk_922[draggable=true] { 1453 | cursor: move; 1454 | /* fallback if grab cursor is unsupported */ 1455 | cursor: grab; 1456 | cursor: -webkit-grab; 1457 | } 1458 | 1459 | ._editImageToolbar_uazmk_935 { 1460 | position: absolute; 1461 | right: 0; 1462 | top: 0; 1463 | display: flex; 1464 | gap: var(--spacing-1); 1465 | padding: var(--spacing-1); 1466 | z-index: 1; 1467 | background-color: var(--baseBase); 1468 | border-bottom-left-radius: var(--radius-base); 1469 | } 1470 | 1471 | ._editImageButton_uazmk_939 svg { 1472 | display: block; 1473 | } 1474 | 1475 | ._inlineEditor_uazmk_945 { 1476 | display: inline-flex; 1477 | border-radius: var(--radius-medium); 1478 | padding: var(--spacing-1); 1479 | gap: var(--spacing-2); 1480 | align-items: center; 1481 | background: var(--baseBg); 1482 | } 1483 | 1484 | ._blockEditor_uazmk_954 { 1485 | display: flex; 1486 | justify-content: stretch; 1487 | border-radius: var(--radius-medium); 1488 | padding: var(--spacing-2); 1489 | gap: var(--spacing-2); 1490 | align-items: center; 1491 | background: var(--baseBg); 1492 | } 1493 | 1494 | ._blockEditor_uazmk_954 ._nestedEditor_uazmk_963 { 1495 | flex-grow: 1; 1496 | } 1497 | 1498 | ._nestedEditor_uazmk_963 { 1499 | background: var(--basePageBg); 1500 | padding: var(--spacing-1) var(--spacing-2); 1501 | border-radius: var(--radius-medium); 1502 | } 1503 | 1504 | ._nestedEditor_uazmk_963>p { 1505 | margin: 0; 1506 | } 1507 | 1508 | ._nestedEditor_uazmk_963:focus { 1509 | outline: none; 1510 | } 1511 | 1512 | ._genericComponentName_uazmk_982 { 1513 | font-size: var(--text-sm); 1514 | color: var(--baseText); 1515 | padding-right: var(--spacing-2); 1516 | } 1517 | 1518 | ._diffSourceToggle_uazmk_988 { 1519 | border-radius: var(--radius-medium); 1520 | display: flex; 1521 | } 1522 | 1523 | ._diffSourceToggle_uazmk_988 ._toolbarToggleItem_uazmk_206 { 1524 | padding: 0; 1525 | } 1526 | 1527 | ._diffSourceToggle_uazmk_988 ._toolbarToggleItem_uazmk_206>span { 1528 | display: block; 1529 | padding: var(--spacing-1) var(--spacing-1); 1530 | } 1531 | 1532 | ._selectWithLabel_uazmk_1002 { 1533 | display: flex; 1534 | align-items: center; 1535 | gap: var(--spacing-2); 1536 | margin-left: var(--spacing-2); 1537 | } 1538 | 1539 | ._selectWithLabel_uazmk_1002>label { 1540 | font-size: var(--text-sm); 1541 | } 1542 | 1543 | ._selectWithLabel_uazmk_1002 ._selectTrigger_uazmk_307 { 1544 | border: 1px solid var(--baseBorder); 1545 | } 1546 | 1547 | ._toolbarTitleMode_uazmk_1017 { 1548 | font-size: var(--text-sm); 1549 | margin-left: var(--spacing-2); 1550 | } 1551 | 1552 | 1553 | ._imageControlWrapperResizing_uazmk_1023 { 1554 | touch-action: none; 1555 | } 1556 | 1557 | ._imageResizer_uazmk_1027 { 1558 | display: block; 1559 | width: 7px; 1560 | height: 7px; 1561 | position: absolute; 1562 | background-color: var(--accentText); 1563 | border: 1px solid var(--baseBg); 1564 | } 1565 | 1566 | ._imageResizer_uazmk_1027._imageResizerN_uazmk_1036 { 1567 | top: -6px; 1568 | left: 48%; 1569 | cursor: n-resize; 1570 | } 1571 | 1572 | ._imageResizer_uazmk_1027._imageResizerNe_uazmk_1042 { 1573 | top: -6px; 1574 | right: -6px; 1575 | cursor: ne-resize; 1576 | } 1577 | 1578 | ._imageResizer_uazmk_1027._imageResizerE_uazmk_1048 { 1579 | bottom: 48%; 1580 | right: -6px; 1581 | cursor: e-resize; 1582 | } 1583 | 1584 | ._imageResizer_uazmk_1027._imageResizerSe_uazmk_1054 { 1585 | bottom: -2px; 1586 | right: -6px; 1587 | cursor: nwse-resize; 1588 | } 1589 | 1590 | ._imageResizer_uazmk_1027._imageResizerS_uazmk_1054 { 1591 | bottom: -2px; 1592 | left: 48%; 1593 | cursor: s-resize; 1594 | } 1595 | 1596 | ._imageResizer_uazmk_1027._imageResizerSw_uazmk_1066 { 1597 | bottom: -2px; 1598 | left: -6px; 1599 | cursor: sw-resize; 1600 | } 1601 | 1602 | ._imageResizer_uazmk_1027._imageResizerW_uazmk_1072 { 1603 | bottom: 48%; 1604 | left: -6px; 1605 | cursor: w-resize; 1606 | } 1607 | 1608 | ._imageResizer_uazmk_1027._imageResizerNw_uazmk_1078 { 1609 | top: -6px; 1610 | left: -6px; 1611 | cursor: nw-resize; 1612 | } 1613 | 1614 | ._placeholder_uazmk_1084 { 1615 | color: var(--baseSolid); 1616 | overflow: hidden; 1617 | position: absolute; 1618 | top: 0; 1619 | padding: var(--spacing-3); 1620 | text-overflow: ellipsis; 1621 | -webkit-user-select: none; 1622 | -moz-user-select: none; 1623 | user-select: none; 1624 | white-space: nowrap; 1625 | display: inline-block; 1626 | pointer-events: none; 1627 | } 1628 | 1629 | ._rootContentEditableWrapper_uazmk_1097 { 1630 | position: relative; 1631 | } 1632 | 1633 | 1634 | 1635 | ._downshiftContainer_uazmk_1103 { 1636 | display: flex; 1637 | flex-direction: column; 1638 | align-items: stretch; 1639 | } 1640 | 1641 | ._downshiftInputWrapper_uazmk_1109 { 1642 | display: flex; 1643 | align-items: center; 1644 | background-color: var(--baseBase); 1645 | 1646 | border-radius: var(--radius-base); 1647 | border: 1px solid var(--baseBorder); 1648 | } 1649 | 1650 | ._downshiftInputWrapper_uazmk_1109[data-visible-dropdown=true] { 1651 | border-bottom-left-radius: var(--radius-none); 1652 | border-bottom-right-radius: var(--radius-none); 1653 | border-bottom-width: 0; 1654 | } 1655 | 1656 | ._downshiftInputWrapper_uazmk_1109>button { 1657 | border: 0; 1658 | background-color: transparent; 1659 | font-size: inherit; 1660 | -webkit-appearance: none; 1661 | -moz-appearance: none; 1662 | appearance: none; 1663 | all: unset; 1664 | box-sizing: border-box; 1665 | cursor: default; 1666 | padding-right: var(--spacing-2); 1667 | } 1668 | 1669 | ._downshiftInput_uazmk_1109 { 1670 | border: 0; 1671 | background-color: transparent; 1672 | font-size: inherit; 1673 | -webkit-appearance: none; 1674 | -moz-appearance: none; 1675 | appearance: none; 1676 | all: unset; 1677 | box-sizing: border-box; 1678 | cursor: default; 1679 | width: 20rem; 1680 | padding: var(--spacing-2) var(--spacing-3); 1681 | font-size: var(--text-sm); 1682 | } 1683 | 1684 | ._downshiftInput_uazmk_1109::-moz-placeholder { 1685 | color: var(--baseBorder); 1686 | } 1687 | 1688 | ._downshiftInput_uazmk_1109::placeholder { 1689 | color: var(--baseBorder); 1690 | } 1691 | 1692 | ._downshiftAutocompleteContainer_uazmk_1140 { 1693 | position: relative; 1694 | } 1695 | 1696 | ._downshiftAutocompleteContainer_uazmk_1140 ul { 1697 | all: unset; 1698 | box-sizing: border-box; 1699 | position: absolute; 1700 | font-size: var(--text-sm); 1701 | width: 100%; 1702 | display: none; 1703 | border-bottom-left-radius: var(--radius-medium); 1704 | border-bottom-right-radius: var(--radius-medium); 1705 | max-height: var(--spacing-48); 1706 | overflow-x: hidden; 1707 | overflow-y: auto; 1708 | border: 1px solid var(--baseBorder); 1709 | border-top-width: 0; 1710 | background-color: var(--baseBase); 1711 | } 1712 | 1713 | ._downshiftAutocompleteContainer_uazmk_1140 ul[data-visible=true] { 1714 | display: block; 1715 | } 1716 | 1717 | ._downshiftAutocompleteContainer_uazmk_1140 ul li { 1718 | padding: var(--spacing-2) var(--spacing-3); 1719 | white-space: nowrap; 1720 | margin-bottom: var(--spacing-1); 1721 | overflow-x: hidden; 1722 | text-overflow: ellipsis; 1723 | } 1724 | 1725 | ._downshiftAutocompleteContainer_uazmk_1140 ul li[data-selected=true] { 1726 | background-color: var(--baseBgSubtle); 1727 | } 1728 | 1729 | ._downshiftAutocompleteContainer_uazmk_1140 ul li[data-highlighted=true] { 1730 | background-color: var(--baseBgHover); 1731 | } 1732 | 1733 | ._downshiftAutocompleteContainer_uazmk_1140 ul li:last-of-type { 1734 | border-bottom-left-radius: var(--radius-medium); 1735 | border-bottom-right-radius: var(--radius-medium); 1736 | } 1737 | 1738 | ._textInput_uazmk_1186 { 1739 | all: unset; 1740 | border-radius: var(--radius-base); 1741 | border: 1px solid var(--baseBorder); 1742 | background-color: var(--baseBase); 1743 | padding: var(--spacing-2) var(--spacing-3); 1744 | } 1745 | 1746 | form._multiFieldForm_uazmk_1194 { 1747 | display: flex; 1748 | flex-direction: column; 1749 | padding: var(--spacing-2); 1750 | gap: var(--spacing-2); 1751 | } 1752 | 1753 | form._multiFieldForm_uazmk_1194 ._formField_uazmk_1200 { 1754 | display: flex; 1755 | flex-direction: column; 1756 | gap: var(--spacing-2); 1757 | } 1758 | 1759 | form._multiFieldForm_uazmk_1194 ._formField_uazmk_1200 label { 1760 | font-size: var(--text-xs); 1761 | } 1762 | 1763 | ._markdownParseError_uazmk_1211 { 1764 | border-radius: var(--radius-base); 1765 | border: 1px solid var(--error-color); 1766 | padding: var(--spacing-2); 1767 | margin-block: var(--spacing-2); 1768 | color: var(--error-color); 1769 | font-size: var(--text-xs); 1770 | } 1771 | 1772 | ._popupContainer_uazmk_1220 { 1773 | position: relative; 1774 | z-index: 2; 1775 | } 1776 | 1777 | ._inputSizer_uazmk_1225 { 1778 | display: inline-grid; 1779 | vertical-align: baseline; 1780 | align-items: center; 1781 | position: relative; 1782 | } 1783 | 1784 | ._inputSizer_uazmk_1225::after, 1785 | ._inputSizer_uazmk_1225 input { 1786 | width: auto; 1787 | min-width: 1rem; 1788 | grid-area: 1 / 2; 1789 | font: inherit; 1790 | margin: 0; 1791 | padding: 0 2px; 1792 | resize: none; 1793 | background: none; 1794 | -webkit-appearance: none; 1795 | -moz-appearance: none; 1796 | appearance: none; 1797 | border: none; 1798 | color: inherit; 1799 | } 1800 | 1801 | ._inputSizer_uazmk_1225 span { 1802 | padding: 0.25em; 1803 | } 1804 | 1805 | ._inputSizer_uazmk_1225::after { 1806 | content: attr(data-value); 1807 | white-space: pre-wrap; 1808 | } 1809 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1810 | --blue-1: #fbfdff; 1811 | --blue-2: #f4faff; 1812 | --blue-3: #e6f4fe; 1813 | --blue-4: #d5efff; 1814 | --blue-5: #c2e5ff; 1815 | --blue-6: #acd8fc; 1816 | --blue-7: #8ec8f6; 1817 | --blue-8: #5eb1ef; 1818 | --blue-9: #0090ff; 1819 | --blue-10: #0588f0; 1820 | --blue-11: #0d74ce; 1821 | --blue-12: #113264; 1822 | } 1823 | 1824 | @supports (color: color(display-p3 1 1 1)) { 1825 | @media (color-gamut: p3) { 1826 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1827 | --blue-1: color(display-p3 0.986 0.992 0.999); 1828 | --blue-2: color(display-p3 0.96 0.979 0.998); 1829 | --blue-3: color(display-p3 0.912 0.956 0.991); 1830 | --blue-4: color(display-p3 0.853 0.932 1); 1831 | --blue-5: color(display-p3 0.788 0.894 0.998); 1832 | --blue-6: color(display-p3 0.709 0.843 0.976); 1833 | --blue-7: color(display-p3 0.606 0.777 0.947); 1834 | --blue-8: color(display-p3 0.451 0.688 0.917); 1835 | --blue-9: color(display-p3 0.247 0.556 0.969); 1836 | --blue-10: color(display-p3 0.234 0.523 0.912); 1837 | --blue-11: color(display-p3 0.15 0.44 0.84); 1838 | --blue-12: color(display-p3 0.102 0.193 0.379); 1839 | } 1840 | } 1841 | } 1842 | 1843 | ._dark_1tncs_1, ._dark-theme_1tncs_1 { 1844 | --blue-1: #0d1520; 1845 | --blue-2: #111927; 1846 | --blue-3: #0d2847; 1847 | --blue-4: #003362; 1848 | --blue-5: #004074; 1849 | --blue-6: #104d87; 1850 | --blue-7: #205d9e; 1851 | --blue-8: #2870bd; 1852 | --blue-9: #0090ff; 1853 | --blue-10: #3b9eff; 1854 | --blue-11: #70b8ff; 1855 | --blue-12: #c2e6ff; 1856 | } 1857 | 1858 | @supports (color: color(display-p3 1 1 1)) { 1859 | @media (color-gamut: p3) { 1860 | ._dark_1tncs_1, ._dark-theme_1tncs_1 { 1861 | --blue-1: color(display-p3 0.057 0.081 0.122); 1862 | --blue-2: color(display-p3 0.072 0.098 0.147); 1863 | --blue-3: color(display-p3 0.078 0.154 0.27); 1864 | --blue-4: color(display-p3 0.033 0.197 0.37); 1865 | --blue-5: color(display-p3 0.08 0.245 0.441); 1866 | --blue-6: color(display-p3 0.14 0.298 0.511); 1867 | --blue-7: color(display-p3 0.195 0.361 0.6); 1868 | --blue-8: color(display-p3 0.239 0.434 0.72); 1869 | --blue-9: color(display-p3 0.247 0.556 0.969); 1870 | --blue-10: color(display-p3 0.344 0.612 0.973); 1871 | --blue-11: color(display-p3 0.49 0.72 1); 1872 | --blue-12: color(display-p3 0.788 0.898 0.99); 1873 | } 1874 | } 1875 | } 1876 | 1877 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1878 | --slate-1: #fcfcfd; 1879 | --slate-2: #f9f9fb; 1880 | --slate-3: #f0f0f3; 1881 | --slate-4: #e8e8ec; 1882 | --slate-5: #e0e1e6; 1883 | --slate-6: #d9d9e0; 1884 | --slate-7: #cdced6; 1885 | --slate-8: #b9bbc6; 1886 | --slate-9: #8b8d98; 1887 | --slate-10: #80838d; 1888 | --slate-11: #60646c; 1889 | --slate-12: #1c2024; 1890 | } 1891 | 1892 | @supports (color: color(display-p3 1 1 1)) { 1893 | @media (color-gamut: p3) { 1894 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1895 | --slate-1: color(display-p3 0.988 0.988 0.992); 1896 | --slate-2: color(display-p3 0.976 0.976 0.984); 1897 | --slate-3: color(display-p3 0.94 0.941 0.953); 1898 | --slate-4: color(display-p3 0.908 0.909 0.925); 1899 | --slate-5: color(display-p3 0.88 0.881 0.901); 1900 | --slate-6: color(display-p3 0.85 0.852 0.876); 1901 | --slate-7: color(display-p3 0.805 0.808 0.838); 1902 | --slate-8: color(display-p3 0.727 0.733 0.773); 1903 | --slate-9: color(display-p3 0.547 0.553 0.592); 1904 | --slate-10: color(display-p3 0.503 0.512 0.549); 1905 | --slate-11: color(display-p3 0.379 0.392 0.421); 1906 | --slate-12: color(display-p3 0.113 0.125 0.14); 1907 | } 1908 | } 1909 | } 1910 | 1911 | ._dark_1tncs_1, ._dark-theme_1tncs_1 { 1912 | --slate-1: #111113; 1913 | --slate-2: #18191b; 1914 | --slate-3: #212225; 1915 | --slate-4: #272a2d; 1916 | --slate-5: #2e3135; 1917 | --slate-6: #363a3f; 1918 | --slate-7: #43484e; 1919 | --slate-8: #5a6169; 1920 | --slate-9: #696e77; 1921 | --slate-10: #777b84; 1922 | --slate-11: #b0b4ba; 1923 | --slate-12: #edeef0; 1924 | } 1925 | 1926 | @supports (color: color(display-p3 1 1 1)) { 1927 | @media (color-gamut: p3) { 1928 | ._dark_1tncs_1, ._dark-theme_1tncs_1 { 1929 | --slate-1: color(display-p3 0.067 0.067 0.074); 1930 | --slate-2: color(display-p3 0.095 0.098 0.105); 1931 | --slate-3: color(display-p3 0.13 0.135 0.145); 1932 | --slate-4: color(display-p3 0.156 0.163 0.176); 1933 | --slate-5: color(display-p3 0.183 0.191 0.206); 1934 | --slate-6: color(display-p3 0.215 0.226 0.244); 1935 | --slate-7: color(display-p3 0.265 0.28 0.302); 1936 | --slate-8: color(display-p3 0.357 0.381 0.409); 1937 | --slate-9: color(display-p3 0.415 0.431 0.463); 1938 | --slate-10: color(display-p3 0.469 0.483 0.514); 1939 | --slate-11: color(display-p3 0.692 0.704 0.728); 1940 | --slate-12: color(display-p3 0.93 0.933 0.94); 1941 | } 1942 | } 1943 | } 1944 | 1945 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1946 | --grass-1: #fbfefb; 1947 | --grass-2: #f5fbf5; 1948 | --grass-3: #e9f6e9; 1949 | --grass-4: #daf1db; 1950 | --grass-5: #c9e8ca; 1951 | --grass-6: #b2ddb5; 1952 | --grass-7: #94ce9a; 1953 | --grass-8: #65ba74; 1954 | --grass-9: #46a758; 1955 | --grass-10: #3e9b4f; 1956 | --grass-11: #2a7e3b; 1957 | --grass-12: #203c25; 1958 | } 1959 | 1960 | @supports (color: color(display-p3 1 1 1)) { 1961 | @media (color-gamut: p3) { 1962 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1963 | --grass-1: color(display-p3 0.986 0.996 0.985); 1964 | --grass-2: color(display-p3 0.966 0.983 0.964); 1965 | --grass-3: color(display-p3 0.923 0.965 0.917); 1966 | --grass-4: color(display-p3 0.872 0.94 0.865); 1967 | --grass-5: color(display-p3 0.811 0.908 0.802); 1968 | --grass-6: color(display-p3 0.733 0.864 0.724); 1969 | --grass-7: color(display-p3 0.628 0.803 0.622); 1970 | --grass-8: color(display-p3 0.477 0.72 0.482); 1971 | --grass-9: color(display-p3 0.38 0.647 0.378); 1972 | --grass-10: color(display-p3 0.344 0.598 0.342); 1973 | --grass-11: color(display-p3 0.263 0.488 0.261); 1974 | --grass-12: color(display-p3 0.151 0.233 0.153); 1975 | } 1976 | } 1977 | } 1978 | 1979 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1980 | --cyan-1: #fafdfe; 1981 | --cyan-2: #f2fafb; 1982 | --cyan-3: #def7f9; 1983 | --cyan-4: #caf1f6; 1984 | --cyan-5: #b5e9f0; 1985 | --cyan-6: #9ddde7; 1986 | --cyan-7: #7dcedc; 1987 | --cyan-8: #3db9cf; 1988 | --cyan-9: #00a2c7; 1989 | --cyan-10: #0797b9; 1990 | --cyan-11: #107d98; 1991 | --cyan-12: #0d3c48; 1992 | } 1993 | 1994 | @supports (color: color(display-p3 1 1 1)) { 1995 | @media (color-gamut: p3) { 1996 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 1997 | --cyan-1: color(display-p3 0.982 0.992 0.996); 1998 | --cyan-2: color(display-p3 0.955 0.981 0.984); 1999 | --cyan-3: color(display-p3 0.888 0.965 0.975); 2000 | --cyan-4: color(display-p3 0.821 0.941 0.959); 2001 | --cyan-5: color(display-p3 0.751 0.907 0.935); 2002 | --cyan-6: color(display-p3 0.671 0.862 0.9); 2003 | --cyan-7: color(display-p3 0.564 0.8 0.854); 2004 | --cyan-8: color(display-p3 0.388 0.715 0.798); 2005 | --cyan-9: color(display-p3 0.282 0.627 0.765); 2006 | --cyan-10: color(display-p3 0.264 0.583 0.71); 2007 | --cyan-11: color(display-p3 0.08 0.48 0.63); 2008 | --cyan-12: color(display-p3 0.108 0.232 0.277); 2009 | } 2010 | } 2011 | } 2012 | 2013 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 2014 | --amber-1: #fefdfb; 2015 | --amber-2: #fefbe9; 2016 | --amber-3: #fff7c2; 2017 | --amber-4: #ffee9c; 2018 | --amber-5: #fbe577; 2019 | --amber-6: #f3d673; 2020 | --amber-7: #e9c162; 2021 | --amber-8: #e2a336; 2022 | --amber-9: #ffc53d; 2023 | --amber-10: #ffba18; 2024 | --amber-11: #ab6400; 2025 | --amber-12: #4f3422; 2026 | } 2027 | 2028 | @supports (color: color(display-p3 1 1 1)) { 2029 | @media (color-gamut: p3) { 2030 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 2031 | --amber-1: color(display-p3 0.995 0.992 0.985); 2032 | --amber-2: color(display-p3 0.994 0.986 0.921); 2033 | --amber-3: color(display-p3 0.994 0.969 0.782); 2034 | --amber-4: color(display-p3 0.989 0.937 0.65); 2035 | --amber-5: color(display-p3 0.97 0.902 0.527); 2036 | --amber-6: color(display-p3 0.936 0.844 0.506); 2037 | --amber-7: color(display-p3 0.89 0.762 0.443); 2038 | --amber-8: color(display-p3 0.85 0.65 0.3); 2039 | --amber-9: color(display-p3 1 0.77 0.26); 2040 | --amber-10: color(display-p3 0.959 0.741 0.274); 2041 | --amber-11: color(display-p3 0.64 0.4 0); 2042 | --amber-12: color(display-p3 0.294 0.208 0.145); 2043 | } 2044 | } 2045 | } 2046 | 2047 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 2048 | --red-1: #fffcfc; 2049 | --red-2: #fff7f7; 2050 | --red-3: #feebec; 2051 | --red-4: #ffdbdc; 2052 | --red-5: #ffcdce; 2053 | --red-6: #fdbdbe; 2054 | --red-7: #f4a9aa; 2055 | --red-8: #eb8e90; 2056 | --red-9: #e5484d; 2057 | --red-10: #dc3e42; 2058 | --red-11: #ce2c31; 2059 | --red-12: #641723; 2060 | } 2061 | 2062 | @supports (color: color(display-p3 1 1 1)) { 2063 | @media (color-gamut: p3) { 2064 | :root, ._light_1tncs_1, ._light-theme_1tncs_1 { 2065 | --red-1: color(display-p3 0.998 0.989 0.988); 2066 | --red-2: color(display-p3 0.995 0.971 0.971); 2067 | --red-3: color(display-p3 0.985 0.925 0.925); 2068 | --red-4: color(display-p3 0.999 0.866 0.866); 2069 | --red-5: color(display-p3 0.984 0.812 0.811); 2070 | --red-6: color(display-p3 0.955 0.751 0.749); 2071 | --red-7: color(display-p3 0.915 0.675 0.672); 2072 | --red-8: color(display-p3 0.872 0.575 0.572); 2073 | --red-9: color(display-p3 0.83 0.329 0.324); 2074 | --red-10: color(display-p3 0.798 0.294 0.285); 2075 | --red-11: color(display-p3 0.744 0.234 0.222); 2076 | --red-12: color(display-p3 0.36 0.115 0.143); 2077 | } 2078 | } 2079 | } 2080 | 2081 | ._bold_1tncs_10 { 2082 | font-weight: bold; 2083 | } 2084 | 2085 | ._italic_1tncs_14 { 2086 | font-style: italic; 2087 | } 2088 | 2089 | ._underline_1tncs_18 { 2090 | text-decoration: underline; 2091 | } 2092 | 2093 | ._bold_1tncs_10 { 2094 | font-weight: 700; 2095 | } 2096 | 2097 | ._italic_1tncs_14 { 2098 | font-style: italic; 2099 | } 2100 | 2101 | ._underline_1tncs_18 { 2102 | text-decoration: underline 2103 | } 2104 | 2105 | ._strikethrough_1tncs_34 { 2106 | text-decoration: line-through 2107 | } 2108 | 2109 | ._underlineStrikethrough_1tncs_38 { 2110 | text-decoration: underline line-through 2111 | } 2112 | 2113 | ._subscript_1tncs_42 { 2114 | font-size: .8em; 2115 | vertical-align: sub !important 2116 | } 2117 | 2118 | ._superscript_1tncs_47 { 2119 | font-size: .8em; 2120 | vertical-align: super 2121 | } 2122 | 2123 | ._code_1tncs_52 { 2124 | background-color: var(--baseBg); 2125 | padding: 1px .25rem; 2126 | font-family: var(--font-mono); 2127 | font-size: 94% 2128 | } 2129 | 2130 | ._nestedListItem_1tncs_59 { 2131 | list-style: none; 2132 | list-style-type: none; 2133 | } 2134 | 2135 | ._nestedListItem_1tncs_59:before, 2136 | ._nestedListItem_1tncs_59:after { 2137 | display: none; 2138 | } 2139 | 2140 | ._listitem_1tncs_69 { 2141 | margin: var(--spacing-2) 0; 2142 | } 2143 | 2144 | ._listItemChecked_1tncs_73, 2145 | ._listItemUnchecked_1tncs_74 { 2146 | position: relative; 2147 | margin-left: 0; 2148 | margin-right: 0; 2149 | margin-inline-start: -1rem; 2150 | padding-left: var(--spacing-6); 2151 | padding-right: var(--spacing-6); 2152 | list-style-type: none; 2153 | outline: none; 2154 | } 2155 | 2156 | ._listItemChecked_1tncs_73 { 2157 | text-decoration: line-through; 2158 | } 2159 | 2160 | ._listItemUnchecked_1tncs_74:before, 2161 | ._listItemChecked_1tncs_73:before { 2162 | content: ''; 2163 | width: var(--spacing-4); 2164 | height: var(--spacing-4); 2165 | top: 0; 2166 | left: 0; 2167 | cursor: pointer; 2168 | display: block; 2169 | background-size: cover; 2170 | position: absolute; 2171 | } 2172 | 2173 | ._listItemUnchecked_1tncs_74[dir='rtl']:before, 2174 | ._listItemChecked_1tncs_73[dir='rtl']:before { 2175 | left: auto; 2176 | right: 0; 2177 | } 2178 | 2179 | ._listItemUnchecked_1tncs_74:focus:before, 2180 | ._listItemChecked_1tncs_73:focus:before { 2181 | box-shadow: 0 0 0 2px var(--accentBgActive); 2182 | border-radius: var(--radius-small); 2183 | } 2184 | 2185 | ._listItemUnchecked_1tncs_74:before { 2186 | border: 1px solid var(--baseBorder); 2187 | border-radius: var(--radius-small); 2188 | } 2189 | 2190 | ._listItemChecked_1tncs_73:before { 2191 | border: 1px solid var(--accentBorder); 2192 | border-radius: var(--radius-small); 2193 | background-color: var(--accentSolid); 2194 | background-repeat: no-repeat; 2195 | } 2196 | 2197 | ._listItemChecked_1tncs_73:after { 2198 | content: ''; 2199 | cursor: pointer; 2200 | border-color: var(--baseBase); 2201 | border-style: solid; 2202 | position: absolute; 2203 | display: block; 2204 | top: var(--spacing-0_5); 2205 | width: var(--spacing-1); 2206 | left: var(--spacing-1_5); 2207 | right: var(--spacing-1_5); 2208 | height: var(--spacing-2); 2209 | transform: rotate(45deg); 2210 | border-width: 0 var(--spacing-0_5) var(--spacing-0_5) 0; 2211 | } 2212 | 2213 | ._nestedListItem_1tncs_59 { 2214 | list-style-type: none; 2215 | } 2216 | 2217 | ._nestedListItem_1tncs_59:before, 2218 | ._nestedListItem_1tncs_59:after { 2219 | display: none; 2220 | } 2221 | 2222 | ._admonitionDanger_1tncs_151, 2223 | ._admonitionInfo_1tncs_152, 2224 | ._admonitionNote_1tncs_153, 2225 | ._admonitionTip_1tncs_154, 2226 | ._admonitionCaution_1tncs_155 { 2227 | padding: var(--spacing-2); 2228 | margin-top: var(--spacing-2); 2229 | margin-bottom: var(--spacing-2); 2230 | border-left: 3px solid var(--admonitionBorder); 2231 | background-color: var(--admonitionBg); 2232 | } 2233 | 2234 | ._admonitionInfo_1tncs_152 { 2235 | --admonitionBorder: var(--admonitionInfoBorder); 2236 | --admonitionBg: var(--admonitionInfoBg); 2237 | } 2238 | 2239 | ._admonitionTip_1tncs_154 { 2240 | --admonitionBorder: var(--admonitionTipBorder); 2241 | --admonitionBg: var(--admonitionTipBg); 2242 | } 2243 | 2244 | ._admonitionCaution_1tncs_155 { 2245 | --admonitionBorder: var(--admonitionCautionBorder); 2246 | --admonitionBg: var(--admonitionCautionBg); 2247 | } 2248 | 2249 | ._admonitionDanger_1tncs_151 { 2250 | --admonitionBorder: var(--admonitionDangerBorder); 2251 | --admonitionBg: var(--admonitionDangerBg); 2252 | } 2253 | 2254 | ._admonitionNote_1tncs_153 { 2255 | --admonitionBorder: var(--admonitionNoteBorder); 2256 | --admonitionBg: var(--admonitionNoteBg); 2257 | } 2258 | 2259 | ._mdxExpression_1tncs_188 { 2260 | font-family: var(--font-mono); 2261 | font-size: 84%; 2262 | color: var(--accentText); 2263 | } 2264 | 2265 | ._mdxExpression_1tncs_188 input:focus-visible { 2266 | outline: none; 2267 | } 2268 | 2269 | .editor-content-container { 2270 | max-width: calc(100vw - 1.5rem); 2271 | } 2272 | 2273 | .editor-content p { 2274 | white-space: normal; 2275 | } 2276 | 2277 | .editor-content button { 2278 | color: var(--baseTextContrast); 2279 | } --------------------------------------------------------------------------------