mirror of https://github.com/MaxLeiter/Drift
				
				
				
			Custom tabs
							parent
							
								
									45c2e59105
								
							
						
					
					
						commit
						3c5dcc24ac
					
				@ -0,0 +1,84 @@
 | 
			
		||||
import * as RadixTabs from "@radix-ui/react-tabs"
 | 
			
		||||
import FormattingIcons from "app/(posts)/new/components/edit-document-list/edit-document/formatting-icons"
 | 
			
		||||
import { ChangeEvent, useRef } from "react"
 | 
			
		||||
import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor"
 | 
			
		||||
import Preview, { StaticPreview } from "../preview"
 | 
			
		||||
import styles from "./tabs.module.css"
 | 
			
		||||
 | 
			
		||||
type Props = RadixTabs.TabsProps & {
 | 
			
		||||
	isEditing: boolean
 | 
			
		||||
	defaultTab: "preview" | "edit"
 | 
			
		||||
	handleOnContentChange?: (e: ChangeEvent<HTMLTextAreaElement>) => void
 | 
			
		||||
	onPaste?: (e: any) => void
 | 
			
		||||
	title?: string
 | 
			
		||||
	content?: string
 | 
			
		||||
	preview?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function DocumentTabs({
 | 
			
		||||
	isEditing,
 | 
			
		||||
	defaultTab,
 | 
			
		||||
	handleOnContentChange,
 | 
			
		||||
	onPaste,
 | 
			
		||||
	title,
 | 
			
		||||
	content,
 | 
			
		||||
	preview,
 | 
			
		||||
	...props
 | 
			
		||||
}: Props) {
 | 
			
		||||
	const codeEditorRef = useRef<TextareaMarkdownRef>(null)
 | 
			
		||||
 | 
			
		||||
	const handleTabChange = (newTab: string) => {
 | 
			
		||||
		if (newTab === "preview") {
 | 
			
		||||
			codeEditorRef.current?.focus()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (
 | 
			
		||||
		<RadixTabs.Root
 | 
			
		||||
			{...props}
 | 
			
		||||
			onValueChange={handleTabChange}
 | 
			
		||||
			className={styles.root}
 | 
			
		||||
			defaultValue={defaultTab}
 | 
			
		||||
		>
 | 
			
		||||
			<RadixTabs.List className={styles.list}>
 | 
			
		||||
				<RadixTabs.Trigger value="edit" className={styles.trigger}>
 | 
			
		||||
					{isEditing ? "Edit" : "Raw"}
 | 
			
		||||
				</RadixTabs.Trigger>
 | 
			
		||||
				<RadixTabs.Trigger value="preview" className={styles.trigger}>
 | 
			
		||||
					{isEditing ? "Preview" : "Rendered"}
 | 
			
		||||
				</RadixTabs.Trigger>
 | 
			
		||||
			</RadixTabs.List>
 | 
			
		||||
			<RadixTabs.Content value="edit">
 | 
			
		||||
				<FormattingIcons textareaRef={codeEditorRef} />
 | 
			
		||||
				<div
 | 
			
		||||
					style={{
 | 
			
		||||
						marginTop: 6,
 | 
			
		||||
						display: "flex",
 | 
			
		||||
						flexDirection: "column"
 | 
			
		||||
					}}
 | 
			
		||||
				>
 | 
			
		||||
					<TextareaMarkdown.Wrapper ref={codeEditorRef}>
 | 
			
		||||
						<textarea
 | 
			
		||||
							readOnly={!isEditing}
 | 
			
		||||
							onPaste={onPaste ? onPaste : undefined}
 | 
			
		||||
							ref={codeEditorRef}
 | 
			
		||||
							placeholder=""
 | 
			
		||||
							value={content}
 | 
			
		||||
							onChange={handleOnContentChange}
 | 
			
		||||
							// TODO: Textarea should grow to fill parent if height == 100%
 | 
			
		||||
							style={{ flex: 1, minHeight: 350 }}
 | 
			
		||||
							// className={styles.textarea}
 | 
			
		||||
						/>
 | 
			
		||||
					</TextareaMarkdown.Wrapper>
 | 
			
		||||
				</div>
 | 
			
		||||
			</RadixTabs.Content>
 | 
			
		||||
			<RadixTabs.Content value="preview">
 | 
			
		||||
				{isEditing ? (
 | 
			
		||||
					<Preview height={"100%"} title={title} content={content} />
 | 
			
		||||
				) : (
 | 
			
		||||
					<StaticPreview height={"100%"} preview={preview || ""} />
 | 
			
		||||
				)}
 | 
			
		||||
			</RadixTabs.Content>
 | 
			
		||||
		</RadixTabs.Root>
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
.root {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list {
 | 
			
		||||
	flex-shrink: 0;
 | 
			
		||||
	display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.trigger {
 | 
			
		||||
	width: 80px;
 | 
			
		||||
	height: 30px;
 | 
			
		||||
	margin: 4px 0;
 | 
			
		||||
	font-family: inherit;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	justify-content: center;
 | 
			
		||||
	font-size: 15px;
 | 
			
		||||
	line-height: 1;
 | 
			
		||||
	user-select: none;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	transition: color 0.1s ease;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.trigger:hover {
 | 
			
		||||
	background-color: var(--lighter-gray);
 | 
			
		||||
	color: var(--fg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.trigger:first-child {
 | 
			
		||||
	border-top-left-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.trigger:last-child {
 | 
			
		||||
	border-top-right-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.trigger[data-state="active"] {
 | 
			
		||||
	color: var(--darkest-gray);
 | 
			
		||||
	box-shadow: inset 0 -1px 0 0 currentColor, 0 1px 0 0 currentColor;
 | 
			
		||||
}
 | 
			
		||||
@ -1,62 +1,68 @@
 | 
			
		||||
.wrapper {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-direction: row;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	/* font-size: 1rem; */
 | 
			
		||||
	height: 2.5rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input {
 | 
			
		||||
  height: 2.5rem;
 | 
			
		||||
  border-radius: var(--inline-radius);
 | 
			
		||||
  background: var(--bg);
 | 
			
		||||
  color: var(--fg);
 | 
			
		||||
  border: 1px solid var(--light-gray);
 | 
			
		||||
  padding: 0 var(--gap-half);
 | 
			
		||||
  outline: none;
 | 
			
		||||
  transition: border-color var(--transition);
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
	height: 2.5rem;
 | 
			
		||||
	border-radius: var(--inline-radius);
 | 
			
		||||
	background: var(--bg);
 | 
			
		||||
	color: var(--fg);
 | 
			
		||||
	border: 1px solid var(--border);
 | 
			
		||||
	padding: 0 var(--gap-half);
 | 
			
		||||
	outline: none;
 | 
			
		||||
	transition: border-color var(--transition);
 | 
			
		||||
	display: flex;
 | 
			
		||||
	justify-content: center;
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.withLabel {
 | 
			
		||||
	/* if with label, then left border should be flat */
 | 
			
		||||
	border-top-left-radius: 0;
 | 
			
		||||
	border-bottom-left-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input::placeholder {
 | 
			
		||||
  font-size: 1rem;
 | 
			
		||||
	/* font-size: 1rem; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input:focus {
 | 
			
		||||
  border-color: var(--input-border-focus);
 | 
			
		||||
	border-color: var(--light-gray);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.label {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  width: initial;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  pointer-events: none;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  padding: 0 var(--gap-half);
 | 
			
		||||
  color: var(--fg);
 | 
			
		||||
  background-color: var(--light-gray);
 | 
			
		||||
  border-top-left-radius: var(--radius);
 | 
			
		||||
  border-bottom-left-radius: var(--radius);
 | 
			
		||||
  border-top: 1px solid var(--input-border);
 | 
			
		||||
  border-left: 1px solid var(--input-border);
 | 
			
		||||
  border-bottom: 1px solid var(--input-border);
 | 
			
		||||
  font-size: inherit;
 | 
			
		||||
  line-height: 1;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
	display: inline-flex;
 | 
			
		||||
	width: initial;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
	pointer-events: none;
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	padding: 0 var(--gap-half);
 | 
			
		||||
	color: var(--darker-gray);
 | 
			
		||||
	background-color: var(--lighter-gray);
 | 
			
		||||
	border-top-left-radius: var(--radius);
 | 
			
		||||
	border-bottom-left-radius: var(--radius);
 | 
			
		||||
	border-top: 1px solid var(--input-border);
 | 
			
		||||
	border-left: 1px solid var(--input-border);
 | 
			
		||||
	border-bottom: 1px solid var(--input-border);
 | 
			
		||||
	line-height: 1;
 | 
			
		||||
	white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-width: 768px) {
 | 
			
		||||
  .wrapper {
 | 
			
		||||
    margin-bottom: var(--gap);
 | 
			
		||||
  }
 | 
			
		||||
	.wrapper {
 | 
			
		||||
		margin-bottom: var(--gap);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.input:disabled {
 | 
			
		||||
  background-color: var(--lighter-gray);
 | 
			
		||||
  color: var(--fg);
 | 
			
		||||
  cursor: not-allowed;  
 | 
			
		||||
	background-color: var(--lighter-gray);
 | 
			
		||||
	color: var(--fg);
 | 
			
		||||
	cursor: not-allowed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue