diff --git a/src/components/Composer.tsx b/src/components/Composer.tsx
index fcd38f7..5ab7e23 100644
--- a/src/components/Composer.tsx
+++ b/src/components/Composer.tsx
@@ -1,9 +1,11 @@
import { StyleSheet, TextInput, View } from "react-native";
import { Text } from "./primitive/Text";
+import { Button } from "./primitive/Button";
import { useContext, useEffect, useMemo, useState } from "react";
import { AuthContext } from "../context/AuthContext";
import { Profile, resolveProfile } from "../lib/profile";
import { RichTextEditor } from "../lib/richtext/editor";
+import { useRouter } from "expo-router";
const styles = StyleSheet.create({
composerHeader: {
@@ -30,8 +32,17 @@ const styles = StyleSheet.create({
borderBottomWidth: 1,
borderColor: "#313131",
},
- composerEditBox: {
- color: "#fff",
+
+ composerFooter: {
+ backgroundColor: "#434343",
+ padding: 10,
+ paddingHorizontal: 15,
+ gap: 10,
+ flexDirection: "row",
+ justifyContent: "flex-end",
+
+ borderBottomWidth: 1,
+ borderColor: "#313131",
},
});
@@ -51,19 +62,44 @@ function ComposerHeader() {
}
function ComposerBody() {
-
return (
-
+
+
+ );
+}
+
+function ComposerFooter({
+ onPublish,
+ onCancel,
+}: {
+ onPublish: () => void;
+ onCancel: () => void;
+}) {
+ return (
+
+
+
);
}
export default function Composer() {
+ const router = useRouter()
+
+ const dismiss = () => {
+ router.canDismiss() ? router.dismiss() : router.navigate('/')
+ }
+
+ const publish = () => {
+ // dismiss()
+ }
+
return (
+
);
}
diff --git a/src/components/primitive/Button.tsx b/src/components/primitive/Button.tsx
new file mode 100644
index 0000000..485c245
--- /dev/null
+++ b/src/components/primitive/Button.tsx
@@ -0,0 +1,41 @@
+import { Pressable, StyleSheet, Text } from "react-native";
+
+const styles = StyleSheet.create({
+ button: {
+ userSelect: "none",
+ paddingVertical: 4,
+ paddingHorizontal: 15,
+ minWidth: 70,
+ alignItems: "center",
+ borderRadius: 20,
+ borderWidth: 2,
+ borderColor: "#a4a4a4",
+ },
+ buttonPrimary: {
+ backgroundColor: "#0084ff",
+ borderColor: "#0084ff",
+ },
+ buttonText: {
+ color: "#fff",
+ fontSize: 15,
+ },
+});
+
+export function Button({
+ text,
+ onPress,
+ primary,
+}: {
+ text: string;
+ onPress?: () => void;
+ primary?: boolean;
+}) {
+ return (
+ onPress() : undefined}
+ >
+ {text}
+
+ );
+}
diff --git a/src/lib/richtext/editor-dom.tsx b/src/lib/richtext/editor-dom.tsx
index 6e011b2..f7ac17e 100644
--- a/src/lib/richtext/editor-dom.tsx
+++ b/src/lib/richtext/editor-dom.tsx
@@ -2,9 +2,15 @@
import { useCallback, useState } from "react";
import { StyleSheet } from "react-native";
-import { createEditor } from "slate";
+import { createEditor, Editor, Path, Selection } from "slate";
import { withHistory } from "slate-history";
-import { Editable, RenderElementProps, Slate, withReact } from "slate-react";
+import {
+ Editable,
+ ReactEditor,
+ RenderElementProps,
+ Slate,
+ withReact,
+} from "slate-react";
const formatStyles = {
default: {
@@ -41,12 +47,32 @@ const formatStyles = {
const formatStyleMap = new Map(Object.entries(formatStyles));
function ParagraphElement(props: RenderElementProps) {
- const appliedStyle = formatStyleMap.get((props.element as any)?.format) ?? formatStyles.regular;
- return
{props.children}
;
+ const appliedStyle =
+ formatStyleMap.get((props.element as any)?.format) ?? formatStyles.regular;
+ return (
+
+ {props.children}
+
+ );
+}
+
+function isEmptySelection(selection: Selection) {
+ return (
+ selection?.anchor === undefined ||
+ (Path.compare(selection?.anchor.path, selection.focus.path) === 0 &&
+ selection.anchor.offset == selection.focus.offset)
+ );
}
-export function DOMEditor() {
- const [slate] = useState(() => withReact(withHistory(createEditor())));
+export function DOMEditor({
+ onMoveToolbar,
+}: {
+ onMoveToolbar: (pos?: DOMRect) => void;
+}) {
+ const [editor] = useState(() => withReact(withHistory(createEditor())));
const initialValue = [
{
@@ -57,16 +83,36 @@ export function DOMEditor() {
const renderElement = useCallback((props: RenderElementProps) => {
switch ((props.element as any).type) {
- case 'paragraph':
+ case "paragraph":
return ;
default:
- return <>>
+ return <>>;
}
}, []);
+ const selectionChange = (selection: Selection) => {
+ const empty = isEmptySelection(selection);
+ if (empty) {
+ onMoveToolbar(undefined);
+ } else {
+ const node = ReactEditor.toDOMNode(
+ editor,
+ editor.node(selection!.anchor)[0],
+ );
+ onMoveToolbar(node.getBoundingClientRect());
+ }
+ };
+
return (
-
-
+
+ onMoveToolbar(undefined)}
+ />
);
}
diff --git a/src/lib/richtext/editor.tsx b/src/lib/richtext/editor.tsx
index aa8886d..b6c28ce 100644
--- a/src/lib/richtext/editor.tsx
+++ b/src/lib/richtext/editor.tsx
@@ -1,13 +1,65 @@
-import {
- ViewProps,
-} from "react-native";
+import { Pressable, StyleSheet, View, ViewProps } from "react-native";
import { DOMEditor } from "./editor-dom";
+import { useState } from "react";
+import FontAwesome from "@expo/vector-icons/FontAwesome";
+const styles = StyleSheet.create({
+ toolbar: {
+ position: "fixed",
+ backgroundColor: "#7f7f7f",
+ padding: 8,
+ borderRadius: 7,
+ flexDirection: "row",
+ gap: 8,
+ },
+ toolbarButton: {},
+});
+
+// function FormatMenu() {
+// return
+// }
+
+function ToolbarButton({
+ icon,
+ onPress,
+}: {
+ icon: React.ComponentProps["name"];
+ onPress?: () => void;
+}) {
+ return (
+
+
+
+ );
+}
+
+function Toolbar({ pos }: { pos: [number, number] }) {
+ return (
+
+
+
+
+
+
+ );
+}
export function RichTextEditor({
style,
minHeight,
...props
}: ViewProps & { minHeight?: number }) {
- return
+ const [pos, setPos] = useState<[number, number] | undefined>(undefined);
+ const onMoveToolbar = (rect?: DOMRect) => {
+ setPos(rect ? [rect.left, rect.top - rect.height - 20] : undefined);
+ };
+
+ return (
+
+
+ {pos && }
+
+ );
}