Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
210dced
update: add extract as svg feature
meetzaveri Jun 5, 2026
761e16c
fix: bug fixes based on issue #84
meetzaveri Jun 5, 2026
2db36ca
update: add opacity property tests and change default font to caveat …
meetzaveri Jun 6, 2026
3eb1eef
Merge pull request #97 from craftbase-org/extract-svg
meetzaveri Jun 6, 2026
075cab5
update: add reordering (z-order positioning) feature for elements in …
meetzaveri Jun 7, 2026
f07e2e1
update: add reorder option to edit toolbar (elementProperties)
meetzaveri Jun 7, 2026
2df5bab
update: add reorder section to claude context
meetzaveri Jun 7, 2026
5b6a572
Merge pull request #101 from craftbase-org/positioning
meetzaveri Jun 7, 2026
8b3730a
update: add port (connector) for selectionController
meetzaveri Jun 7, 2026
7970bc1
update: add nearbyPort radar search and auto connect arrow to shape f…
meetzaveri Jun 11, 2026
d50bf9c
update: add restack and resort arrow tail/head endpoint to avoid over…
meetzaveri Jun 12, 2026
7b40c06
update: reconcileZOrder now gets inactive while group selection is ac…
meetzaveri Jun 12, 2026
d8e4735
Merge pull request #103 from craftbase-org/ux-port-edges
meetzaveri Jun 12, 2026
e2d90b0
update: add perf logs and preload elements module chunks (shapes only)
meetzaveri Jun 13, 2026
604bbed
update: prefetch groupobject chunk and add perf logs for it as well
meetzaveri Jun 13, 2026
380b48d
update: parallel load factory chunks + atomic commit to build all me…
meetzaveri Jun 13, 2026
4255bcb
update: deselect group on undo operation
meetzaveri Jun 13, 2026
d1b3bd0
update: remove scaffolding for performance testing (perf logs)
meetzaveri Jun 13, 2026
be4e511
update: gate port-connectors behind feature flag
meetzaveri Jun 13, 2026
0c4da91
update: fix text selection bug + add sitemap + change essential shades
meetzaveri Jun 14, 2026
c6bab44
update: persist welcome sketch elements
meetzaveri Jun 14, 2026
6782608
update: enable pan mode for desktop as well
meetzaveri Jun 14, 2026
5997094
Merge pull request #104 from craftbase-org/perf-improvements
meetzaveri Jun 14, 2026
26715ac
update: bump version to 0.7.8
meetzaveri Jun 14, 2026
623c979
minor: stroke color change for selection controller
meetzaveri Jun 14, 2026
9665ae2
fix: bug fix for text accepting fill property
meetzaveri Jun 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Reusable React UI components.
- `userDetailsPopup.tsx` - User information popup
- `sidebar.css` - Sidebar styles

**Element defaults vs. selected-shape edits:** `src/utils/applyProperty.ts` (`createApplyProperty`) is the single mutation path behind `elementProperties.tsx`. Every property change (1) updates the matching default via `useElementDefaults` setters, then (2) if a shape is selected, applies the same change to that shape. So editing a property with nothing selected just sets the default; editing with a shape selected sets both. Defaults store `null` for `strokeType: 'solid'` (matching what `primary.tsx` feeds new shapes); DB rows store the literal `'solid'`/`'dashed'`/`'dotted'`.
**Element defaults vs. selected-shape edits:** `src/utils/applyProperty.ts` (`createApplyProperty`) is the single mutation path behind `elementProperties.tsx`. Every property change (1) updates the matching default via `useElementDefaults` setters, then (2) if a shape is selected, applies the same change to that shape. So editing a property with nothing selected just sets the default; editing with a shape selected sets both. Defaults store `null` for `strokeType: 'solid'` (matching what `primary.tsx` feeds new shapes); DB rows store the literal `'solid'`/`'dashed'`/`'dotted'`.

- **`common/`**: Shared utility components
- `button.tsx` - Base button component
Expand Down Expand Up @@ -302,7 +302,39 @@ See detailed notes in `.claude/context/` for feature-specific implementation det
- `.claude/context/floating-toolbar.md` - Floating toolbar activation and structure
- `.claude/context/undo-history.md` - Undo/history stack: action entry shapes, `recordToHistoryLog`, and `undoLastAction()` as the canonical rollback for any failed mutation
- `.claude/context/responsive-design.md` - When to use Tailwind responsive prefixes vs `useMediaQueryUtils` hook; breakpoint values for both; the core decision rule
- `.claude/context/font-guide.md` - Font system: Geist (UI chrome), Fraunces (branding/headings), Caveat (canvas sketch); CSS variables, Tailwind config, and usage rules per area
- `.claude/context/font-guide.md` - Font system: Geist (UI chrome), Fraunces (branding/headings), Caveat Brush (canvas sketch); CSS variables, Tailwind config, and usage rules per area
- `claude/context/reorder.md` - How reording/positioning of elements in Z-Axis (Z-order) works in craftbase

## Port connectors (connectable arrows)

Connectors are `arrowLine` elements whose tail/head can dock onto a shape's
edge **port**.

- **Port** — a connection point floated just outside each edge midpoint
(n/e/s/w) of a `rectangle` selection box. Rendered + hit-tested in
`src/canvas/selectionController.ts`; geometry in `src/utils/shapePorts.ts`
(`getShapePortPoint`). Clicking a port pulls out a connector whose tail is
pinned there (`startPortConnector` in `src/newCanvas.tsx`).
- **Nearby-port radar** — while an arrow endpoint is being dragged, the cursor
is the probe: `findNearestPort` (`shapePorts.ts`) finds the closest port in
range (`PORT_RADAR_RADIUS`), which the controller highlights with the amber
pulsing `portGlow` ring + the dashed `nearbyPortExpectedShape` skeleton around
the candidate shape. A **one-off magnetic snap** glues the endpoint to that
port; pulling past the threshold releases it (never forced). On release while
docked, the binding is committed (`updatePortRadar`/`applyPendingPortConnection`).
- **Binding columns** — attachment is stored as 4 fields on the arrow row:
`tailShapeId`/`tailEdge` and `headShapeId`/`headEdge` (`*Edge` = `n/e/s/w-resize`).
Reverse lookup is derived by scanning the store (no shape-side columns).
`reanchorArrowsForShape`/`persistBoundArrows` keep a docked endpoint glued when
the bound shape moves/resizes.

**Persisted-mode caveat:** these 4 fields currently live only on Two.js
`elementData` + the local/localStorage store — they are **not** columns in the
Hasura `components` table or `src/schema/generated.ts`. So bindings work in
**local mode (`/`)** but do **not** survive a reload on a **saved board
(`/board/:id`)** yet. Enabling persisted mode needs: `ALTER TABLE` to add the 4
nullable columns + track them in Hasura, `yarn codegen`, and adding them to the
board-load query so they read back.

### Component schema (from DB)

Expand Down
26 changes: 26 additions & 0 deletions .claude/context/reorder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Reorder/Positioning of elements

In 2d space, we need to adjust how elements behave on z-axis. For that we need to reorder children of two group to achieve such expectations.

In craftbase, we have four options

- Bring to front (Brings it to the foremost top of the order, at [N])
- Bring forward (Brings 1 order up , at[current+1])
- Send Backward (Sends 1 order down, at [current-1])
- Send to Back (Sends to last of the order, at [0])

This is being triggered by three inputs from user

- Keyboard shortcuts
- Context Menu (opens on right click)
- Element Properties Toolbar or edit toolbar

Shortcuts are

```
`]` = Bring Forward, `[` = Send Backward, `⌘` + `]` = Bring to Front, `⌘` + `[` = Send to Back (and Ctrl+… on Windows/Linux)
```

## Business logic

We attach a property to each component called `position` which determines its position in Z-Axis or two's scene. The core logic is implemented at `reorderSelected` fn of newCanvas.tsx file .
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Craftbase

A minimal whiteboard you can open and start drawing on. No signup, no setup, no empty-state tutorial to click through — the canvas is just there waiting.
A minimal online whiteboard you can open and start drawing on. No signup, no setup, no empty-state tutorial to click through — the canvas is just there waiting.

**Try it: [craftbase.org](https://craftbase.org)**

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.7.7
0.7.8
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap"
href="https://fonts.googleapis.com/css2?family=Caveat:wght@700&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&family=Caveat+Brush&display=swap"
rel="stylesheet"
/>
<title>Craftbase - minimal whiteboard for builders</title>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "craftbase",
"version": "0.7.7",
"version": "0.7.8",
"private": true,
"main": "src/lib.ts",
"module": "src/lib.ts",
Expand Down
2 changes: 2 additions & 0 deletions public/robots.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

Sitemap: https://craftbase.org/sitemap.xml
33 changes: 33 additions & 0 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://craftbase.org/</loc>
<lastmod>2026-06-14</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://craftbase.org/home</loc>
<lastmod>2026-06-14</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://craftbase.org/embeddable-whiteboard</loc>
<lastmod>2026-06-14</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://craftbase.org/support</loc>
<lastmod>2026-06-14</lastmod>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://craftbase.org/privacy</loc>
<lastmod>2026-06-14</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
</urlset>
9 changes: 8 additions & 1 deletion src/App.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
:root {
--font-ui: 'Geist', system-ui, sans-serif;
--font-display: 'Fraunces', Georgia, serif;
--font-sketch: 'Caveat', cursive;
--font-sketch: 'Caveat Brush';
--font-mono: 'Geist Mono', monospace;
--font-caveat-brush: 'Caveat Brush', cursive;

--color-canvas: #f5f0e8;
--color-sidebar: #ede8dc;
Expand All @@ -18,6 +19,12 @@
--color-border-card: #c4b89a;
}

.caveat-brush-regular {
font-family: 'Caveat Brush', cursive;
font-weight: 400;
font-style: normal;
}

body {
margin: 0;
font-family: var(--font-ui);
Expand Down
5 changes: 5 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import BoardViewContainer from './views/Board'
import HomePageViewContainer from './views/Home'
import SupportViewContainer from './views/Support'
import PrivacyViewContainer from './views/Privacy'
import EmbeddableViewContainer from './views/Embeddable'
import CraftbaseLoader from './components/common/craftbaseLoader'

import routes from './routes'
Expand Down Expand Up @@ -171,6 +172,10 @@ class App extends Component {
path={routes.privacy}
element={<PrivacyViewContainer />}
/>
<Route
path={routes.embeddable}
element={<EmbeddableViewContainer />}
/>
</Routes>
</div>
</AppInit>
Expand Down
1 change: 1 addition & 0 deletions src/assets/bring-forward.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/bring-to-front.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/cards.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/chevron-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/layers.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/send-backward.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/send-to-back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/settings.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading