init: the first public commit for AFFiNE

This commit is contained in:
DarkSky
2022-07-22 15:49:21 +08:00
commit e3e3741393
1451 changed files with 108124 additions and 0 deletions
@@ -0,0 +1,29 @@
import { services } from '@toeverything/datasource/db-service';
interface DuplicatePageProps {
workspaceId: string;
pageId: string;
}
export const duplicatePage = async ({
workspaceId,
pageId,
}: DuplicatePageProps) => {
//create page
const newPage = await services.api.editorBlock.create({
workspace: workspaceId,
type: 'page' as const,
});
//add page to tree
await services.api.pageTree.addNextPageToWorkspace(
workspaceId,
pageId,
newPage.id
);
//copy source page to new page
await services.api.editorBlock.copyPage(workspaceId, pageId, newPage.id);
return {
workspaceId,
pageId: newPage.id,
};
};
@@ -0,0 +1,57 @@
import TurndownService from 'turndown';
export const fileExporter = {
exportFile: (filename: string, text: string, format: string) => {
const element = document.createElement('a');
element.setAttribute(
'href',
'data:' + format + ';charset=utf-8,' + encodeURIComponent(text)
);
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
},
decorateHtml: (pageTitle: string, htmlContent: string) => {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${pageTitle}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
</head>
<body>
<div style="margin:20px auto;width:800px" >
<div style="background-color: #fff;box-shadow: 0px 0px 5px #ccc;padding: 10px;">
${htmlContent}
</div>
</div>
</body>
</html>`;
},
decoreateAffineBrand: (pageTitle: string) => {
return pageTitle + ` Created in Affine`;
},
exportHtml: (pageTitle: string, htmlContent: string) => {
fileExporter.exportFile(
fileExporter.decoreateAffineBrand(pageTitle) + '.html',
fileExporter.decorateHtml(pageTitle, htmlContent),
'text/html'
);
},
exportMarkdown: (pageTitle: string, htmlContent: string) => {
const turndownService = new TurndownService();
const markdown = turndownService.turndown(htmlContent);
fileExporter.exportFile(
fileExporter.decoreateAffineBrand(pageTitle) + '.md',
markdown,
'text/plain'
);
},
};
@@ -0,0 +1,50 @@
import { useState, useEffect } from 'react';
import { services } from '@toeverything/datasource/db-service';
const UNTITLED = 'untitled';
interface GetPageTitleProps {
workspaceId: string;
pageId: string;
}
export const getPageTitle = async ({
workspaceId,
pageId,
}: GetPageTitleProps) => {
return await services.api.editorBlock
.get({ workspace: workspaceId, ids: [pageId] })
.then(blockData => {
if (!blockData?.[0]) {
return UNTITLED;
}
return blockData[0].properties.text.value.map(v => v.text).join('');
});
};
const getPageLastUpdated = async ({
workspaceId,
pageId,
}: GetPageTitleProps) => {
return await services.api.editorBlock
.getBlock(workspaceId, pageId)
.then(block => {
if (!block) {
return null;
}
return block.lastUpdated;
});
};
export const usePageLastUpdated = ({
workspaceId,
pageId,
}: GetPageTitleProps) => {
const [lastUpdated, setLastUpdated] = useState<number>(Date.now());
useEffect(() => {
getPageLastUpdated({ workspaceId, pageId }).then(d => {
setLastUpdated(d ? d : Date.now());
});
}, [workspaceId, pageId]);
return lastUpdated;
};
@@ -0,0 +1,42 @@
import { ClipboardParse } from '@toeverything/components/editor-core';
import { createEditor } from '@toeverything/components/affine-editor';
import { fileExporter } from './file-exporter';
interface CreateClipboardParseProps {
workspaceId: string;
rootBlockId: string;
}
const createClipboardParse = ({
workspaceId,
rootBlockId,
}: CreateClipboardParseProps) => {
const editor = createEditor(workspaceId);
editor.setRootBlockId(rootBlockId);
return new ClipboardParse(editor);
};
interface ExportHandlerProps extends CreateClipboardParseProps {
title: string;
}
export const exportHtml = async ({
workspaceId,
rootBlockId,
title,
}: ExportHandlerProps) => {
const clipboardParse = createClipboardParse({ workspaceId, rootBlockId });
const htmlContent = await clipboardParse.page2html();
fileExporter.exportHtml(title, htmlContent);
};
export const exportMarkdown = async ({
workspaceId,
rootBlockId,
title,
}: ExportHandlerProps) => {
const clipboardParse = createClipboardParse({ workspaceId, rootBlockId });
const htmlContent = await clipboardParse.page2html();
fileExporter.exportMarkdown(title, htmlContent);
};
@@ -0,0 +1,6 @@
export { duplicatePage } from './duplicate-page';
export { exportHtml, exportMarkdown } from './handle-export';
export { getPageTitle, usePageLastUpdated } from './get-page-info';
export { importWorkspace, exportWorkspace } from './inspector-workspace';
export { useWorkspaceAndPageId } from './use-workspace-page';
export { useReadingMode } from './use-reading-mode';
@@ -0,0 +1,32 @@
/**
* @deprecated debugging method, deprecated
*/
export const importWorkspace = (workspaceId: string) => {
//@ts-ignore
window.client
.inspector()
.load()
.then(() => {
window.location.href = `/${workspaceId}/`;
});
};
/**
* @deprecated debugging method, deprecated
*/
export const exportWorkspace = () => {
//@ts-ignore
window.client.inspector().save();
};
/**
* @deprecated debugging method, deprecated
*/
export const clearWorkspace = async workspaceId => {
//@ts-ignore
if (window.confirm('Are you sure you want to clear the workspace?')) {
//@ts-ignore
await window.client.inspector().clear();
window.location.href = `/${workspaceId}/`;
}
};
@@ -0,0 +1,23 @@
import {
useShowSettingsSidebar,
useShowSpaceSidebar,
} from '@toeverything/datasource/state';
/**
* TODO: This is not Reading Mode, it needs to be discussed later, so I will write it now
*/
export const useReadingMode = () => {
const { setShowSettingsSidebar } = useShowSettingsSidebar();
const { fixedDisplay, toggleSpaceSidebar } = useShowSpaceSidebar();
const readingMode = !fixedDisplay;
const toggleReadingMode = () => {
toggleSpaceSidebar();
setShowSettingsSidebar(readingMode);
};
return {
readingMode,
toggleReadingMode,
};
};
@@ -0,0 +1,16 @@
import { useParams } from 'react-router-dom';
interface UseWorkspaceAndPageIdReturn {
workspaceId?: string;
pageId?: string;
}
export const useWorkspaceAndPageId = (): UseWorkspaceAndPageIdReturn => {
const params = useParams();
const workspaceId = params['workspace_id'];
const pageId = params['*'].split('/')[0];
return {
workspaceId,
pageId,
};
};