Skip to content

Commit

Permalink
improve: welcome page list of recent files
Browse files Browse the repository at this point in the history
work in progress, welcome page to refresh dynamically
  • Loading branch information
afarago committed Oct 13, 2024
1 parent c2cb457 commit 4a2ba2b
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 22 deletions.
5 changes: 4 additions & 1 deletion src/app/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021-2023 The Pybricks Authors
// Copyright (c) 2021-2024 The Pybricks Authors
import docsPackage from '@pybricks/ide-docs/package.json';

// Definitions for compile-time UI settings.
Expand Down Expand Up @@ -87,3 +87,6 @@ export const zipFileExtension = '.zip';

/** The ZIP file MIME type ('application/zip') */
export const zipFileMimeType = 'application/zip';

/** maximum number of recent file displayed */
export const recentFileCount = 3;
45 changes: 35 additions & 10 deletions src/editor/Welcome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import { Document, Plus } from '@blueprintjs/icons';
import React, { useCallback, useEffect, useRef } from 'react';
import { useDispatch } from 'react-redux';
import Two from 'two.js';
import { useTernaryDarkMode } from 'usehooks-ts';
import { useLocalStorage, useTernaryDarkMode } from 'usehooks-ts';
import { Activity, useActivitiesSelectedActivity } from '../activities/hooks';
import { recentFileCount } from '../app/constants';
import { explorerCreateNewFile } from '../explorer/actions';
import { UUID } from '../fileStorage';
import { editorActivateFile } from './actions';
import { useI18n } from './i18n';
import logoSvg from './logo.svg';
import { RecentFileMetadata } from '.';

const defaultRotation = -Math.PI / 9; // radians
const rotationSpeedIncrement = 0.1; // radians per second
Expand Down Expand Up @@ -100,6 +104,7 @@ const Welcome: React.FunctionComponent<WelcomeProps> = ({ isVisible }) => {

const logo = two.load(logoSvg, (g) => {
g.center();

two.add(logo);
two.play();
});
Expand All @@ -111,7 +116,7 @@ const Welcome: React.FunctionComponent<WelcomeProps> = ({ isVisible }) => {
});

logo.fill = fillColorRef.current;
logo.scale = Math.min(two.width, two.height) / 90;
logo.scale = Math.min(two.width, two.height) / 80;
logo.rotation = stateRef.current.rotation;

two.scene.position.x = two.width / 2;
Expand Down Expand Up @@ -169,9 +174,34 @@ const Welcome: React.FunctionComponent<WelcomeProps> = ({ isVisible }) => {
dispatch(explorerCreateNewFile());
}, [dispatch, setSelectedActivity]);

const handleOpenExplorer = useCallback(() => {
//useCallback
const handleOpenExplorer = (uuid: UUID) => {
setSelectedActivity(Activity.Explorer);
}, [setSelectedActivity]);
dispatch(editorActivateFile(uuid));
};

const [editorRecentFiles] = useLocalStorage('editor.recentFiles', []);
const getRecentFileShortCuts = () => (
<>
{editorRecentFiles
.slice(0, recentFileCount)
.map((fitem: RecentFileMetadata) => (
<dl key={fitem.uuid}>
<dt>
{i18n.translate('welcome.openProject', {
fileName: fitem.path,
})}
</dt>
<dd>
<Button
icon={<Document />}
onClick={() => handleOpenExplorer(fitem.uuid)}
/>
</dd>
</dl>
))}
</>
);

return (
<div
Expand All @@ -183,12 +213,7 @@ const Welcome: React.FunctionComponent<WelcomeProps> = ({ isVisible }) => {
>
<div className="logo" ref={elementRef}></div>
<div className="shortcuts">
<dl>
<dt>{i18n.translate('welcome.openProject')}</dt>
<dd>
<Button icon={<Document />} onClick={handleOpenExplorer} />
</dd>
</dl>
{getRecentFileShortCuts()}
<dl>
<dt>{i18n.translate('welcome.newProject')}</dt>
<dd>
Expand Down
20 changes: 11 additions & 9 deletions src/editor/editor.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2023 The Pybricks Authors
// Copyright (c) 2020-2024 The Pybricks Authors

// Custom styling for the Editor control.

Expand Down Expand Up @@ -76,24 +76,26 @@
justify-content: center;
align-items: center;

// display: block;
width: 100%;
height: 100%;
// max-width: 290px;

.logo {
flex: 1;
display: flex;
min-height: 0;
width: 100%;
height: 100%;
position: absolute;
top: -2%;

svg {
overflow: visible !important;
width: 100%;
height: 100%;
object-fit: contain;
min-height: 10;
flex: 1;
}
}
.shortcuts {
position: relative;
top: +6%;
padding: 20px;
text-align: center;

border-collapse: separate;
border-spacing: 11px 17px;
Expand Down
14 changes: 14 additions & 0 deletions src/editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2024 The Pybricks Authors

import { UUID } from '../fileStorage';

/**
* LocalStorage recent files data type.
*/
export type RecentFileMetadata = Readonly<{
/** A globally unique identifier that serves a a file handle. */
uuid: UUID;
/** The path of the file in storage. */
path: string;
}>;
30 changes: 29 additions & 1 deletion src/editor/sagas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022-2023 The Pybricks Authors
// Copyright (c) 2022-2024 The Pybricks Authors

import type { DatabaseChangeType, IDatabaseChange } from 'dexie-observable/api';
import * as monaco from 'monaco-editor';
Expand All @@ -17,6 +17,7 @@ import {
takeEvery,
} from 'typed-redux-saga/macro';
import { alertsShowAlert } from '../alerts/actions';
import { recentFileCount } from '../app/constants';
import { FileStorageDb, UUID } from '../fileStorage';
import {
fileStorageDidFailToLoadTextFile,
Expand Down Expand Up @@ -67,6 +68,7 @@ import {
import { EditorError } from './error';
import { ActiveFileHistoryManager, OpenFileManager } from './lib';
import { pybricksMicroPythonId } from './pybricksMicroPython';
import { RecentFileMetadata } from '.';

function* handleEditorGetValueRequest(
editor: monaco.editor.ICodeEditor,
Expand Down Expand Up @@ -273,6 +275,32 @@ function* handleEditorActivateFile(

editor.focus();

// store the activated uuid in the recent files queue
let recentFiles = (() => {
try {
return JSON.parse(
localStorage.getItem('editor.recentFiles') ?? '',
) as RecentFileMetadata[];
} catch {
return [];
}
})();

// Check if the file already exists
const fileIndex = recentFiles.findIndex((fitem: RecentFileMetadata) => {
return fitem.uuid === action.uuid;
});
if (fileIndex !== -1) {
recentFiles.splice(fileIndex, 1);
}

const db = yield* getContext<FileStorageDb>('fileStorage');
const metadata = yield* call(() => db.metadata.get(action.uuid));
recentFiles.unshift({ uuid: action.uuid, path: metadata?.path ?? '' }); // Add new (or existing) file to the beginning
recentFiles = [...recentFiles.slice(recentFileCount)]; // Keep only the first 10 items
localStorage.setItem('editor.recentFiles', JSON.stringify(recentFiles));

// signal activation done
yield* put(editorDidActivateFile(action.uuid));
} catch (err) {
yield* put(editorDidFailToActivateFile(action.uuid, ensureError(err)));
Expand Down
2 changes: 1 addition & 1 deletion src/editor/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"welcome": {
"label": "Welcome",
"openProject": "Open existing project",
"openProject": "Open {fileName}",
"newProject": "Open a new project"
}
}

0 comments on commit 4a2ba2b

Please sign in to comment.