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