Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 5 additions & 4 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import ts from 'eslint-config-cheminfo-typescript/base';
import unicorn from 'eslint-config-cheminfo-typescript/unicorn';

export default [

{
ignores: [
'build',
Expand All @@ -14,15 +13,16 @@ export default [
'playwright-report',
'test-results',
'public',
'.yalc',
],
},
...ts,
...unicorn,
...react,
{
files: ["**/pdnd.cts"],
files: ['**/pdnd.cts'],
rules: {
"import/no-extraneous-dependencies": "off",
'import/no-extraneous-dependencies': 'off',
},
},
{
Expand Down Expand Up @@ -54,7 +54,8 @@ export default [
{
name: '@simbathesailor/use-what-changed',
message: 'Remove use-what-changed before committing the code',
}],
},
],
'react/no-unknown-property': ['error', { ignore: ['css'] }],
'react/forbid-dom-props': [
'error',
Expand Down
22 changes: 11 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
"@emotion/styled": "^11.14.1",
"@hookform/resolvers": "^5.1.1",
"@zakodium/nmr-types": "^0.1.0",
"@zakodium/nmrium-core": "^0.1.4",
"@zakodium/nmrium-core-plugins": "^0.1.7",
"@zakodium/nmrium-core": "^0.1.5",
"@zakodium/nmrium-core-plugins": "^0.1.8",
"@zip.js/zip.js": "^2.7.68",
"cheminfo-font": "^1.13.1",
"cheminfo-types": "^1.8.1",
Expand Down
15 changes: 15 additions & 0 deletions src/component/header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import styled from '@emotion/styled';
import { memo, useMemo } from 'react';
import {
FaFilm,
Expand All @@ -9,6 +10,7 @@ import { Toolbar, useFullscreen } from 'react-science/ui';

import { docsBaseUrl } from '../../constants.js';
import { useChartData } from '../context/ChartContext.js';
import { useCore } from '../context/CoreContext.js';
import {
usePreferences,
useWorkspacesList,
Expand All @@ -26,6 +28,7 @@ import AboutUsModal from '../modal/aboutUs/AboutUsModal.js';
import GeneralSettingsModal from '../modal/setting/GeneralSettings.js';
import WorkspaceItem from '../modal/setting/WorkspaceItem.js';
import { options } from '../toolbar/ToolTypes.js';
import { renderCoreSlot } from '../utility/renderCoreSlot.js';

import { AutoPeakPickingOptionPanel } from './AutoPeakPickingOptionPanel.js';
import { HeaderWrapper } from './HeaderWrapper.js';
Expand Down Expand Up @@ -60,6 +63,7 @@ interface HeaderInnerProps {

function HeaderInner(props: HeaderInnerProps) {
const { selectedOptionPanel, height } = props;
const core = useCore();

const {
current: {
Expand Down Expand Up @@ -144,6 +148,10 @@ function HeaderInner(props: HeaderInnerProps) {
alignItems: 'center',
}}
>
<PluginTopBarRight>
{renderCoreSlot(core, 'topbar.right')}
</PluginTopBarRight>

{!hideWorkspaces && (
<DropDownButton
data={workspacesList}
Expand Down Expand Up @@ -242,3 +250,10 @@ export function Header() {
/>
);
}

const PluginTopBarRight = styled.div`
display: flex;
align-items: center;
gap: 5px;
margin-right: 5px;
`;
11 changes: 11 additions & 0 deletions src/component/utility/renderCoreSlot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { NMRiumCore, SupportedUISlot } from '@zakodium/nmrium-core';
import type { ReactNode } from 'react';

export function renderCoreSlot(
core: NMRiumCore,
slot: SupportedUISlot,
): ReactNode[] {
return Array.from(core.slot(slot), ([key, Component]) => (
<Component key={key} slot={slot} />
));
}
10 changes: 10 additions & 0 deletions src/demo/samples.json
Original file line number Diff line number Diff line change
Expand Up @@ -345,5 +345,15 @@
"width": "1000px",
"height": "600px"
}
},
{
"groupName": "Plugin UI",
"children": [
{
"title": "TopBar Plugin",
"file": "./data/cytisine/1H.json",
"view": "PluginUITopBar"
}
]
}
]
97 changes: 97 additions & 0 deletions src/demo/views/PluginUITopBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { IconName } from '@blueprintjs/icons';
import { IconNames } from '@blueprintjs/icons';
import styled from '@emotion/styled';
import init from '@zakodium/nmrium-core-plugins';
import {
createContext,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
import { Toolbar } from 'react-science/ui';

import { NMRium } from '../../component/main/index.js';

import type { ViewProps } from './View.helpers.js';
import { useView } from './View.helpers.js';

const Container = styled.section`
display: flex;
flex-direction: column;
height: 100%;

& > h1 {
font-weight: 700;
font-size: 1.5em;
line-height: 1.4em;
padding: 0.75em;
}
`;

const NMRiumContainer = styled.div`
flex: 1;
`;

const DemoContext = createContext<{
setRandom: () => void;
icon: IconName;
// eslint-disable-next-line @typescript-eslint/no-empty-function
}>({ icon: 'console', setRandom: () => {} });

function DemoTopBarRight() {
const { setRandom, icon } = useContext(DemoContext);

return (
<Toolbar>
<Toolbar.Item
id="demo-topbar-right"
icon={icon}
tooltip="Demo topbar right"
onClick={setRandom}
/>
</Toolbar>
);
}

const core = init([
{
id: 'demo-plugin-topbar',
version: 1,
migrations: [],
ui: {
'topbar.right': DemoTopBarRight,
},
},
]);

const possibleIcons = Object.values(IconNames);
export default function PluginUITopBar(props: ViewProps) {
const [data, otherProps] = useView(props);

const { workspace, customWorkspaces } = otherProps;

const [icon, setIcon] = useState<IconName>('console');
const setRandom = useCallback(() => {
const randomIndex = Math.floor(Math.random() * possibleIcons.length);
setIcon(possibleIcons[randomIndex]);
}, []);
const context = useMemo(() => ({ setRandom, icon }), [icon, setRandom]);

return (
<Container>
<h1>TopBar Plugin</h1>

<NMRiumContainer>
<DemoContext.Provider value={context}>
<NMRium
core={core}
data={data}
{...(workspace && { workspace })}
{...(customWorkspaces && { customWorkspaces })}
/>
</DemoContext.Provider>
</NMRiumContainer>
</Container>
);
}
2 changes: 1 addition & 1 deletion src/demo/views/Test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DropZone } from 'react-science/ui';

import { NMRium } from '../../component/main/index.js';

import { loadData } from './View.js';
import { loadData } from './View.helpers.js';

function searchDeep(obj, searchKey) {
const result: any = [];
Expand Down
41 changes: 41 additions & 0 deletions src/demo/views/View.helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useEffect, useState } from 'react';

import type { BaseViewProps } from './BaseView.js';

export async function loadData(file) {
const response = await fetch(file);
checkStatus(response);
const data = await response.json();
return data;
}

function checkStatus(response) {
if (!response.ok) {
throw new Error(`HTTP ${response.status} - ${response.statusText}`);
}
return response;
}

export interface ViewProps extends Omit<BaseViewProps, 'data'> {
file: string;
baseURL: string;
}

export function useView(props: ViewProps) {
const [data, setData] = useState();

const { file, baseURL, ...otherProps } = props;

useEffect(() => {
if (file) {
void loadData(file).then((d) => {
const _d = JSON.parse(JSON.stringify(d).replaceAll(/\.\/+?/g, baseURL));
setData(_d);
});
} else {
setData(undefined);
}
}, [baseURL, file]);

return [data, otherProps] as const;
}
39 changes: 3 additions & 36 deletions src/demo/views/View.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,9 @@
import { useEffect, useState } from 'react';

import type { BaseViewProps } from './BaseView.js';
import BaseView from './BaseView.js';

export async function loadData(file) {
const response = await fetch(file);
checkStatus(response);
const data = await response.json();
return data;
}

function checkStatus(response) {
if (!response.ok) {
throw new Error(`HTTP ${response.status} - ${response.statusText}`);
}
return response;
}

interface ViewProps extends Omit<BaseViewProps, 'data'> {
file: string;
baseURL: string;
}
import type { ViewProps } from './View.helpers.js';
import { useView } from './View.helpers.js';

export default function View(props: ViewProps) {
const [data, setData] = useState();

const { file, baseURL, ...otherProps } = props;

useEffect(() => {
if (file) {
void loadData(file).then((d) => {
const _d = JSON.parse(JSON.stringify(d).replaceAll(/\.\/+?/g, baseURL));
setData(_d);
});
} else {
setData(undefined);
}
}, [baseURL, file]);
const [data, otherProps] = useView(props);

return <BaseView {...otherProps} data={data} />;
}
1 change: 1 addition & 0 deletions src/demo/views/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export const possibleViews = {
TwoInstances: memo(lazy(() => import('./TwoInstances.js'))),
View: memo(lazy(() => import('./View.js'))),
WebSourceView: memo(lazy(() => import('./WebSourceView.js'))),
PluginUITopBar: memo(lazy(() => import('./PluginUITopBar.js'))),
};
Loading