diff --git a/src/list.jsx b/src/list.jsx
index 5c48abd..49d53b8 100644
--- a/src/list.jsx
+++ b/src/list.jsx
@@ -1,22 +1,15 @@
import { Filesystem } from '@capacitor/filesystem';
import { getPaths } from './get-data.js';
import React, { useState, useEffect, useCallback } from 'react';
-import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
-import { chevronDown } from '@wordpress/icons';
+import { ToolbarButton, ToolbarGroup, Button } from '@wordpress/components';
+import { addCard, archive } from '@wordpress/icons';
+import { useResizeObserver } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { v4 as uuidv4 } from 'uuid';
-import { Read, Write, getTitleFromBlocks } from './read-write.js';
-import Editor from './editor.jsx';
-
-function Title({ item: { path, blocks } }) {
- if (blocks) {
- return getTitleFromBlocks(blocks) || {__('Untitled')};
- }
-
- const title = path?.replace(/(?:\.?[0-9]+)?\.html$/, '');
- return title ? decodeURIComponent(title) : {__('Untitled')};
-}
+import { Read, Write } from './read-write';
+import Editor from './editor';
+import Sidebar from './sidebar.jsx';
function getInitialSelection({ path, blocks }) {
if (path) {
@@ -37,6 +30,7 @@ function getInitialSelection({ path, blocks }) {
export default function Frame({ selectedFolderURL, setSelectedFolderURL }) {
const [currentId, setCurrentId] = useState();
const [items, setItems] = useState([]);
+ const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const setItem = useCallback((id, item) => {
setItems((_items) =>
@@ -66,6 +60,8 @@ export default function Frame({ selectedFolderURL, setSelectedFolderURL }) {
});
}, [selectedFolderURL, setSelectedFolderURL, setCurrentId]);
+ const [observer, { width }] = useResizeObserver();
+
if (!currentId) {
return null;
}
@@ -74,106 +70,167 @@ export default function Frame({ selectedFolderURL, setSelectedFolderURL }) {
return (
<>
-
-
+ 900
+ ? 'calc(100% - 300px)'
+ : '',
+ }}
+ >
+ {observer}
+
+
+ {
+ setIsSidebarOpen(!isSidebarOpen);
+ }}
+ />
+
+
+ {
+ const newItem = { id: uuidv4() };
+ setItems([newItem, ...items]);
+ setCurrentId(newItem.id);
+ setItem(currentId, {
+ blocks: null,
+ });
+ }}
+ />
+
+ {/*
+ {({ onClose }) => (
+ <>
+
+
+
+ {items.map((item) => (
+
+ ))}
+
+
+
- ))}
-
-
-
-
-
- >
+
+
+ >
+ )}
+ */}
+
+
+ {currentItem.blocks && (
+ {
+ setItem(currentItem.id, { blocks });
+ }}
+ />
)}
-
-
-
- {currentItem.blocks && (
- {
- setItem(currentItem.id, { blocks });
- }}
+
+ {((ReadWrite) => (
+
- )}
+ ))(currentItem.blocks ? Write : Read)}
- {((ReadWrite) => (
-
- ))(currentItem.blocks ? Write : Read)}
>
);
}
diff --git a/src/read-write.js b/src/read-write.js
index eff3c8c..b3a7f96 100644
--- a/src/read-write.js
+++ b/src/read-write.js
@@ -67,9 +67,10 @@ export function getTitleFromBlocks(blocks) {
for (const block of blocks) {
const html = getBlockContent(block);
- const textContent = sanitizeFileName(
- html.replace(/<[^>]+>/g, '').trim()
- ).slice(0, 50);
+ const textContent = html
+ .replace(/<[^>]+>/g, '')
+ .trim()
+ .slice(0, 50);
if (textContent) {
return textContent;
}
@@ -84,7 +85,7 @@ function useUpdateFile({ selectedFolderURL, item, setItem }) {
}
const base = path.split('/').slice(0, -1).join('/');
- const title = getTitleFromBlocks(note);
+ const title = sanitizeFileName(getTitleFromBlocks(note));
let newPath;
if (title) {
newPath = base ? base + '/' + title + '.html' : title + '.html';
diff --git a/src/sidebar.jsx b/src/sidebar.jsx
new file mode 100644
index 0000000..733b164
--- /dev/null
+++ b/src/sidebar.jsx
@@ -0,0 +1,57 @@
+import { DataViews } from '@wordpress/dataviews';
+import { __ } from '@wordpress/i18n';
+import React, { useState } from 'react';
+import { getTitleFromBlocks } from './read-write';
+
+function Title({ item: { path, blocks } }) {
+ if (blocks) {
+ return getTitleFromBlocks(blocks) || {__('Untitled')};
+ }
+
+ const title = path?.replace(/(?:\.?[0-9]+)?\.html$/, '');
+ return title ? decodeURIComponent(title) : {__('Untitled')};
+}
+
+export default function SiderBar({ items, setItem, currentId, setCurrentId }) {
+ const [view, setView] = useState({
+ type: 'list',
+ search: '',
+ filters: [],
+ page: 1,
+ perPage: 5,
+ sort: {
+ field: 'path',
+ direction: 'desc',
+ },
+ hiddenFields: [],
+ layout: {},
+ });
+
+ return (
+ ;
+ },
+ },
+ ]}
+ onChangeView={setView}
+ paginationInfo={{
+ totalItems: items.length,
+ totalPages: 1,
+ }}
+ onSelectionChange={([item]) => {
+ setCurrentId(item.id);
+ setItem(currentId, { blocks: null });
+ }}
+ supportedLayouts={['list']}
+ />
+ );
+}
diff --git a/src/style.css b/src/style.css
index 32c4691..db84eee 100644
--- a/src/style.css
+++ b/src/style.css
@@ -28,11 +28,73 @@ body,
font-size: 1em;
}
+#sidebar {
+ position: absolute;
+ top: env(safe-area-inset-top);
+ width: 300px;
+ bottom: 0;
+ overflow-y: auto;
+ border-right: 1px solid #e0e0e0;
+ word-break: break-all;
+}
+
+.dataviews-filters__view-actions {
+ padding: 7px;
+ border-bottom: 1px solid #e0e0e0;
+ position: sticky;
+ top: 0;
+}
+
+.dataviews-view-list__item-wrapper {
+ display: block !important;
+}
+
+.dataviews-view-list__item[aria-pressed="true"] {
+ background-color: #3858e9;
+ color: white;
+ padding: 7px;
+}
+
+.dataviews-view-list__item {
+ padding: 7px;
+ border-radius: 2px
+}
+
+.dataviews-view-list__item > div {
+ display: block !important;
+}
+
+ul.dataviews-view-list {
+ padding: 7px;
+ margin: 0;
+ list-style: none;
+}
+
+ul.dataviews-view-list li {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.dataviews-view-table {
+ padding: 7px
+}
+
+.dataviews-view-list__field {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+#content {
+ height: 100%;
+}
+
#select {
position: absolute;
top: 0;
width: 100%;
- height: calc( env(safe-area-inset-top) + 46px );
+ height: calc( env(safe-area-inset-top) + 47px );
display: flex;
justify-content: start;
align-items: end;
@@ -66,6 +128,7 @@ iframe[name="editor-canvas"] {
}
#select,
+.dataviews-filters__view-actions,
/* .is-unstyled ? */
.components-dropdown__content div.components-popover__content {
backdrop-filter: blur(5px);
@@ -79,7 +142,6 @@ iframe[name="editor-canvas"] {
}
#select .blocknotes-select button {
- border-right: 1px solid #e0e0e0;
padding-right: 1em;
}
diff --git a/tests/mock.spec.js b/tests/mock.spec.js
index 94283b9..642ad95 100644
--- a/tests/mock.spec.js
+++ b/tests/mock.spec.js
@@ -68,13 +68,11 @@ test.describe('Blocknotes', () => {
await expect(emptyBlock).toBeFocused();
- const notesButton = page.getByRole('button', { name: 'Notes' });
-
- await notesButton.click();
+ await page.getByRole('button', { name: 'Notes' }).click();
- await expect(
- page.getByRole('menu', { name: 'Notes' }).getByRole('menuitem')
- ).toHaveText(['New Note', 'Untitled', 'Pick Folder', 'Forget Folder']);
+ await expect(page.getByRole('grid').getByRole('row')).toHaveText([
+ 'Untitled',
+ ]);
await emptyBlock.click();
@@ -84,11 +82,7 @@ test.describe('Blocknotes', () => {
canvas(page).getByRole('document', { name: 'Block: Paragraph' })
).toBeFocused();
- await notesButton.click();
-
- await expect(
- page.getByRole('menu', { name: 'Notes' }).getByRole('menuitem')
- ).toHaveText(['New Note', 'aa', 'Pick Folder', 'Forget Folder']);
+ await expect(page.getByRole('row')).toHaveText(['aa']);
// Nothing should have been saved yet because saving is debounced.
expect(await getPaths(page)).toEqual([]);
@@ -125,19 +119,14 @@ test.describe('Blocknotes', () => {
`);
// Create a second note.
- await notesButton.click();
- await page.getByRole('menuitem', { name: 'New Note' }).click();
+ await page.getByRole('button', { name: 'New Note' }).click();
await page.keyboard.type('b');
- await notesButton.click();
-
- await expect(
- page.getByRole('menu', { name: 'Notes' }).getByRole('menuitem')
- ).toHaveText(['New Note', 'b', 'aaaa', 'Pick Folder', 'Forget Folder']);
+ await expect(page.getByRole('row')).toHaveText(['b', 'aaaa']);
// Immediately switch back to note A.
- await page.getByRole('menuitem', { name: 'aaaa' }).click();
+ await page.getByRole('button', { name: 'aaaa' }).click();
await expect(
canvas(page).getByRole('document', { name: 'Block: Paragraph' })
@@ -220,15 +209,14 @@ test.describe('Blocknotes', () => {
const notesButton = page.getByRole('button', { name: 'Notes' });
- await notesButton.click();
- await page.getByRole('menuitem', { name: 'New Note' }).click();
+ await page.getByRole('button', { name: 'New Note' }).click();
await page.keyboard.type('a');
await page.keyboard.press('Enter');
await page.keyboard.type('2');
await notesButton.click();
- await page.getByRole('menuitem', { name: 'a' }).nth(1).click();
+ await page.getByRole('row', { name: 'a' }).nth(1).click();
await expect(
canvas(page)