Skip to content

Commit

Permalink
adds sortable
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotBraem committed Jan 10, 2025
1 parent 8226d7c commit 6981706
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 30 deletions.
Binary file modified bun.lockb
Binary file not shown.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
]
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@near-js/providers": "^1.0.0",
"@near-wallet-selector/bitte-wallet": "^8.9.13",
"@near-wallet-selector/core": "^8.9.13",
Expand All @@ -46,6 +49,7 @@
"near-api-js": "^4.0.3",
"next": "14.2.13",
"react": "^18",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "^18",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
Expand Down
150 changes: 121 additions & 29 deletions src/components/compose-post.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,103 @@ import { useState, useEffect } from "react";
import { useDraftsStore } from "../store/drafts-store";
import { DraftsModal } from "./drafts-modal";
import { Button } from "./ui/button";
import {
DndContext,
closestCenter,
KeyboardSensor,
PointerSensor,
useSensor,
useSensors,
} from "@dnd-kit/core";
import {
arrayMove,
SortableContext,
sortableKeyboardCoordinates,
useSortable,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";

function SortablePost({ post, index, onTextChange, onRemove }) {
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
isDragging,
} = useSortable({ id: `post-${index}` });

const style = {
transform: CSS.Transform.toString(transform),
transition,
opacity: isDragging ? 0.5 : 1,
};

return (
<div ref={setNodeRef} style={style} className="flex gap-2 sm:px-4 -mx-4 sm:mx-0">
<div className="flex-none w-8">
<div
{...attributes}
{...listeners}
className="sticky top-0 h-[150px] w-8 flex items-center justify-center cursor-grab bg-gray-50 rounded-lg border-2 border-gray-800 shadow-[2px_2px_0_rgba(0,0,0,1)]"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="9" cy="5" r="1" />
<circle cx="9" cy="12" r="1" />
<circle cx="9" cy="19" r="1" />
<circle cx="15" cy="5" r="1" />
<circle cx="15" cy="12" r="1" />
<circle cx="15" cy="19" r="1" />
</svg>
</div>
</div>
<div className="flex-1">
<textarea
value={post.text}
onChange={(e) => onTextChange(index, e.target.value)}
placeholder={`Thread part ${index + 1}`}
maxLength={280}
className="w-full min-h-[150px] px-4 py-4 border-2 border-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none shadow-[2px_2px_0_rgba(0,0,0,1)]"
/>
<div className="flex justify-between items-center mt-1">
<span className="text-sm text-gray-500">
{post.text.length}/280 characters
</span>
<Button
onClick={() => onRemove(index)}
variant="destructive"
size="sm"
>
Remove
</Button>
</div>
</div>
</div>
);
}

// This "widget" handles all of the editing for post content
// Calls "onSubmit" with an array of post objects

export function ComposePost({ onSubmit }) {
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates,
})
);

const [isThreadMode, setIsThreadMode] = useState(false);
const [posts, setPosts] = useState([{ text: "", image: null }]);
const [error, setError] = useState("");
Expand Down Expand Up @@ -106,45 +198,45 @@ export function ComposePost({ onSubmit }) {

{isThreadMode ? (
<div className="space-y-4">
{posts.map((post, index) => (
<div key={index} className="relative">
<textarea
value={post.text}
onChange={(e) => handleTextChange(index, e.target.value)}
placeholder={`Thread part ${index + 1}`}
maxLength={280}
className="w-full min-h-[150px] p-4 border-2 border-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none shadow-[2px_2px_0_rgba(0,0,0,1)]"
/>
<div className="flex justify-between items-center mt-1">
<span className="text-sm text-gray-500">
{post.text.length}/280 characters
</span>
{posts.length > 1 && (
<Button
onClick={() => removeThread(index)}
variant="ghost"
size="sm"
className="text-red-500 hover:text-red-700"
>
Remove
</Button>
)}
</div>
{/* Future image upload UI would go here */}
</div>
))}
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={(event) => {
const { active, over } = event;
if (over && active.id !== over.id) {
const oldIndex = parseInt(active.id.split("-")[1]);
const newIndex = parseInt(over.id.split("-")[1]);
setPosts((posts) => arrayMove(posts, oldIndex, newIndex));
}
}}
>
<SortableContext
items={posts.map((_, i) => `post-${i}`)}
strategy={verticalListSortingStrategy}
>
{posts.map((post, index) => (
<SortablePost
key={`post-${index}`}
post={post}
index={index}
onTextChange={handleTextChange}
onRemove={posts.length > 1 ? removeThread : undefined}
/>
))}
</SortableContext>
</DndContext>
<Button onClick={addThread} className="w-full" size="sm">
+ Add Thread
</Button>
</div>
) : (
<div>
<div className="sm:px-4 -mx-4 sm:mx-0">
<textarea
value={posts[0].text}
onChange={(e) => handleTextChange(0, e.target.value)}
placeholder="What's happening?"
maxLength={280 * 10} // Allow for multiple tweets worth in single mode
className="w-full min-h-[150px] p-4 border-2 border-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none shadow-[2px_2px_0_rgba(0,0,0,1)]"
className="w-full min-h-[150px] px-4 py-4 border-2 border-gray-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none shadow-[2px_2px_0_rgba(0,0,0,1)]"
/>
{/* Future image upload UI would go here */}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/window-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function WindowContainer({ children }) {
className="mx-1 sm:mx-auto min-h-[790px] max-w-4xl border-2 border-gray-800 bg-white shadow-[4px_4px_0_rgba(0,0,0,1)]"
>
<WindowControls />
<div className="p-8">{children}</div>
<div className="sm:p-8 p-2">{children}</div>
</motion.div>
</div>
);
Expand Down

0 comments on commit 6981706

Please sign in to comment.