Skip to content

Commit

Permalink
Merge pull request #110 from Kartore/feat/ui-design
Browse files Browse the repository at this point in the history
デザイン変更
  • Loading branch information
NEKOYASAN authored Sep 12, 2024
2 parents be15340 + dc3134e commit 2a304d0
Show file tree
Hide file tree
Showing 92 changed files with 354 additions and 226 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://fonts.googleapis.com/css2?family=Montserrat:[email protected]&display=swap" rel="stylesheet">
<title>Vite + React + TS</title>
</head>
<body>
Expand Down
11 changes: 11 additions & 0 deletions plop-templates/icon/Icon.tsx.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { HTMLAttributes } from 'react';

export type {{pascalCase name}}Props = HTMLAttributes<SVGElement>;

const {{pascalCase name}} = (props: {{pascalCase name}}Props) => {
return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" {...props}></svg>;
};

{{pascalCase name}}.displayName = '{{pascalCase name}}';

export { {{pascalCase name}} };
23 changes: 23 additions & 0 deletions plopfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,27 @@ export default function Plopfile(plop) {
},
],
});

plop.setGenerator('icon', {
description: 'Create a new icon',
prompts: [
{
type: 'input',
name: 'name',
message: 'Icon name',
},
],
actions: [
{
type: 'add',
path: 'src/components/icons/{{name}}/{{name}}.tsx',
templateFile: 'plop-templates/icon/Icon.tsx.hbs',
},
{
type: 'append',
path: 'src/components/icons/index.ts',
template: "export * from './{{name}}/{{name}}';",
},
],
});
}
48 changes: 21 additions & 27 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import type { LayerSpecification, StyleSpecification } from 'maplibre-gl';
import { MapProvider } from 'react-map-gl';
import { useLocalStorage } from 'usehooks-ts';

import { LayerPanel } from '~/components/editor/LayerPanel/LayerPanel.tsx';
import { MapPanel } from '~/components/editor/MapPanel/MapPanel.tsx';
import { NavigationPanel } from '~/components/editor/NavigationPanel/NavigationPanel.tsx';
import type { onChangeType } from '~/components/editor/PropertiesPanel/LayerPropertiesPanel/utils/LayerUtil/LayerUtil.ts';
import { replaceLayerData } from '~/components/editor/PropertiesPanel/LayerPropertiesPanel/utils/LayerUtil/LayerUtil.ts';
import { PropertiesPanel } from '~/components/editor/PropertiesPanel/PropertiesPanel.tsx';
import type { onChangeType } from '~/components/editor/PropertiesPanel/utils/LayerUtil/LayerUtil.ts';
import { replaceLayerData } from '~/components/editor/PropertiesPanel/utils/LayerUtil/LayerUtil.ts';
import { Header } from '~/components/header/Header';
import { osmLiberty } from '~/samples/osm-liberty.ts';

function App() {
Expand Down Expand Up @@ -38,29 +37,24 @@ function App() {

return (
<MapProvider>
<div className={'grid max-h-screen min-h-screen w-full grid-cols-1 grid-rows-[3rem_1fr]'}>
<Header />
<div className={'flex h-full flex-row overflow-hidden'}>
<LayerPanel
className={'w-1/5 overflow-y-auto'}
layers={mapStyle.layers}
onChangeLayerOrder={handleChangeLayerOrder}
onClickLayer={(layer) => {
setSelectedLayerId(layer.id);
}}
/>
<div className={'flex-1'}>
<MapPanel mapStyle={mapStyle} />
</div>

<div className={'w-1/5 overflow-y-auto'}>
<PropertiesPanel
layer={selectedLayer}
sources={mapStyle.sources}
onChange={handleChangeLayerData}
/>
</div>
</div>
<div className={'relative flex max-h-screen min-h-screen w-full flex-row overflow-hidden'}>
<MapPanel mapStyle={mapStyle} />
<NavigationPanel
className={'absolute top-2 bottom-2 left-2 w-1/5'}
mapStyle={mapStyle}
onChangeLayerOrder={handleChangeLayerOrder}
selectedLayerId={selectedLayerId}
onClickLayer={(layer) => {
setSelectedLayerId(layer.id);
}}
/>

<PropertiesPanel
className={'absolute top-2 right-2 bottom-2 w-1/5'}
layer={selectedLayer}
sources={mapStyle.sources}
onChange={handleChangeLayerData}
/>
</div>
</MapProvider>
);
Expand Down
1 change: 0 additions & 1 deletion src/components/editor/LayerPanel/index.ts

This file was deleted.

5 changes: 3 additions & 2 deletions src/components/editor/MapPanel/MapPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ export const MapPanel: FC<{
latitude: 35.681,
zoom: 15,
}}
style={{ height: '100%', ...style }}
style={{ height: 'auto', width: '100%', ...style }}
mapStyle={mapStyle}
maplibreLogo
maplibreLogo={false}
attributionControl={false}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import type { LayerSpecification } from 'maplibre-gl';

import { osmLiberty } from '~/samples/osm-liberty.ts';

import { LayerPanel } from '.';
import { NavigationPanel } from '.';

const meta = {
component: LayerPanel,
} satisfies Meta<typeof LayerPanel>;
component: NavigationPanel,
} satisfies Meta<typeof NavigationPanel>;

export default meta;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { composeStories } from '@storybook/react';
import { render } from '@testing-library/react';
import { describe } from 'vitest';

import * as Stories from './LayerPanel.stories';
import * as Stories from './NavigationPanel.stories';

const { Default } = composeStories(Stories);

describe('Component: LayerPanel', () => {
describe('Component: NavigationPanel', () => {
describe('Snapshot', () => {
it('Default', () => {
const { asFragment } = render(<Default />);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ComponentPropsWithoutRef, FC } from 'react';
import { useState } from 'react';

import type { DragEndEvent, DragStartEvent, Modifier, UniqueIdentifier } from '@dnd-kit/core';
import type { DragEndEvent, DragStartEvent, Modifier } from '@dnd-kit/core';
import {
DndContext,
DragOverlay,
Expand All @@ -12,29 +12,32 @@ import {
useSensors,
} from '@dnd-kit/core';
import { arrayMove, SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import type { LayerSpecification } from 'maplibre-gl';
import type { LayerSpecification, StyleSpecification } from 'maplibre-gl';
import { createPortal } from 'react-dom';

import { SortableLayerTreeItem } from '~/components/editor/LayerPanel/SortableLayerTreeItem/SortableLayerTreeItem.tsx';
import { SortableLayerTreeItem } from '~/components/editor/NavigationPanel/SortableLayerTreeItem/SortableLayerTreeItem.tsx';
import { cn } from '~/utils/tailwindUtil';

type LayerPanelProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'> & {
layers: LayerSpecification[];
mapStyle: StyleSpecification;
selectedLayerId: LayerSpecification['id'] | null;
onClickLayer: (id: LayerSpecification) => void;
onChangeLayerOrder: (layers: LayerSpecification[]) => void;
};

export const LayerPanel: FC<LayerPanelProps> = ({
export const NavigationPanel: FC<LayerPanelProps> = ({
onChangeLayerOrder,
onClickLayer,
layers,
mapStyle,
className,
selectedLayerId,
...props
}) => {
const [activeId, setActiveId] = useState<UniqueIdentifier | null>(null);
const [activeLayer, setActiveLayer] = useState<LayerSpecification | null>(null);

const handleDragStart = ({ active: { id } }: DragStartEvent) => {
setActiveId(id);
setActiveLayer(mapStyle.layers.find((layer) => layer.id === id) || null);

document.body.style.setProperty('cursor', 'grabbing');
};

Expand All @@ -47,7 +50,7 @@ export const LayerPanel: FC<LayerPanelProps> = ({
if (!over) {
return;
}
const clonedLayers: LayerSpecification[] = JSON.parse(JSON.stringify(layers));
const clonedLayers: LayerSpecification[] = JSON.parse(JSON.stringify(mapStyle.layers));

const activeIndex = clonedLayers.findIndex((layer) => layer.id === active.id);
const overIndex = clonedLayers.findIndex((layer) => layer.id === over.id);
Expand All @@ -56,7 +59,7 @@ export const LayerPanel: FC<LayerPanelProps> = ({
};

const resetState = () => {
setActiveId(null);
setActiveLayer(null);

document.body.style.setProperty('cursor', '');
};
Expand All @@ -78,11 +81,25 @@ export const LayerPanel: FC<LayerPanelProps> = ({
);

return (
<div {...props} className={cn('h-full w-auto', className)}>
<div className={'border-b py-1 px-2'}>
<div
{...props}
className={cn(
'flex h-auto w-auto flex-col rounded-lg border border-gray-300 bg-white',
className
)}
>
<div className={'flex flex-col gap-2 border-b border-b-gray-300 py-4 px-4'}>
<h1 className={'font-[Montserrat] font-bold'}>Kartore</h1>
<h2 className={'font-[Montserrat] font-semibold'}>{mapStyle.name}</h2>

Check failure on line 93 in src/components/editor/NavigationPanel/NavigationPanel.tsx

View workflow job for this annotation

GitHub Actions / test

src/components/editor/NavigationPanel/NavigationPanel.test.tsx > Component: NavigationPanel > Snapshot > Default

TypeError: Cannot read properties of undefined (reading 'name') ❯ NavigationPanel src/components/editor/NavigationPanel/NavigationPanel.tsx:93:69 ❯ renderWithHooks node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js:15486:18 ❯ mountIndeterminateComponent node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js:20103:13 ❯ beginWork node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js:21626:16 ❯ HTMLUnknownElement.callCallback node_modules/.pnpm/[email protected][email protected]/node_modules/react-dom/cjs/react-dom.development.js:4164:14 ❯ HTMLUnknownElement.#callDispatchEventListeners node_modules/.pnpm/[email protected]/node_modules/happy-dom/src/event/EventTarget.ts:286:41 ❯ HTMLUnknownElement.dispatchEvent node_modules/.pnpm/[email protected]/node_modules/happy-dom/src/event/EventTarget.ts:121:35 ❯ HTMLUnknownElement.dispatchEvent node_modules/.pnpm/[email protected]/node_modules/happy-dom/src/nodes/element/Element.ts:1245:29 ❯ HTMLUnknownElement.#goThroughDispatchEventPhases node_modules/.pnpm/[email protected]/node_modules/happy-dom/src/event/EventTarget.ts:184:32 ❯ HTMLUnknownElement.dispatchEvent node_modules/.pnpm/[email protected]/node_modules/happy-dom/src/event/EventTarget.ts:116:38
</div>
<div
className={
'border-b border-b-gray-300 py-2 px-4 font-[Montserrat] text-sm font-medium text-gray-500'
}
>
<h2>Layers</h2>
</div>
<div className={'px-2'}>
<div className={'flex-1 overflow-auto'}>
<DndContext
measuring={{
droppable: {
Expand All @@ -95,15 +112,16 @@ export const LayerPanel: FC<LayerPanelProps> = ({
onDragEnd={handleDragEnd}
>
<SortableContext
items={layers.map((layer) => layer.id)}
items={mapStyle.layers.map((layer) => layer.id)}
strategy={verticalListSortingStrategy}
>
{layers.map((layer) => {
{mapStyle.layers.map((layer) => {
return (
<SortableLayerTreeItem
key={layer.id}
id={layer.id}
indicator={layer.id === activeId}
isSelected={layer.id === selectedLayerId}
layer={layer}
indicator={layer.id === activeLayer?.id}
onClick={() => {
onClickLayer(layer);
}}
Expand All @@ -113,10 +131,10 @@ export const LayerPanel: FC<LayerPanelProps> = ({
</SortableContext>
{createPortal(
<DragOverlay modifiers={[adjustTranslate]}>
{activeId ? <SortableLayerTreeItem id={activeId} clone /> : null}
{activeLayer ? <SortableLayerTreeItem layer={activeLayer} clone /> : null}
</DragOverlay>,
document.body,
`drag-overlay-${activeId}`
`drag-overlay-${activeLayer?.id}`
)}
</DndContext>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import { type ComponentPropsWithoutRef, forwardRef } from 'react';

import type { UniqueIdentifier } from '@dnd-kit/core';
import type { LayerSpecification } from '@maplibre/maplibre-gl-style-spec';

import { LayerIcon } from '~/components/icons';
import { cn } from '~/utils/tailwindUtil';

export type LayerTreeItemProps = {
id: UniqueIdentifier;
indicator?: boolean;
clone?: boolean;
disableInteraction?: boolean;
layer: LayerSpecification;
isSelected?: boolean;
} & Omit<ComponentPropsWithoutRef<'div'>, 'id'>;

export const LayerTreeItem = forwardRef<HTMLDivElement, LayerTreeItemProps>(
({ id, indicator, disableInteraction, clone, className, ...props }, ref) => {
({ layer, indicator, disableInteraction, clone, className, isSelected, ...props }, ref) => {
return (
<div
ref={ref}
{...props}
className={cn(
'flex items-center p-2',
'flex w-full items-center gap-2 py-2 px-4 text-sm text-gray-800',
indicator && 'opacity-60',
clone && 'inline-block',
clone && 'inline-flex',
disableInteraction || clone ? 'pointer-events-none' : 'pointer-events-auto',
isSelected ? 'bg-gray-200' : 'hover:bg-gray-100',
className
)}
>
<p>{id}</p>
<LayerIcon type={layer.type} className={'h-3 w-3 min-w-3 cursor-grab'} />
<p className={'flex-1 overflow-hidden text-ellipsis'}>{layer.id}</p>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import type { CSSProperties, FC } from 'react';

import type { AnimateLayoutChanges} from '@dnd-kit/sortable';
import type { AnimateLayoutChanges } from '@dnd-kit/sortable';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';

import type {
LayerTreeItemProps} from '~/components/editor/LayerPanel/SortableLayerTreeItem/LayerTreeItem/LayerTreeItem.tsx';
import {
LayerTreeItem
} from '~/components/editor/LayerPanel/SortableLayerTreeItem/LayerTreeItem/LayerTreeItem.tsx';
import type { LayerTreeItemProps } from '~/components/editor/NavigationPanel/SortableLayerTreeItem/LayerTreeItem/LayerTreeItem.tsx';
import { LayerTreeItem } from '~/components/editor/NavigationPanel/SortableLayerTreeItem/LayerTreeItem/LayerTreeItem.tsx';

const animateLayoutChanges: AnimateLayoutChanges = ({ isSorting, wasDragging }) =>
!(isSorting || wasDragging);

type SortableLayerTreeItemProps = LayerTreeItemProps;

export const SortableLayerTreeItem: FC<SortableLayerTreeItemProps> = ({ id, ...props }) => {
export const SortableLayerTreeItem: FC<SortableLayerTreeItemProps> = ({ layer, ...props }) => {
const {
attributes,
isSorting,
Expand All @@ -26,7 +23,7 @@ export const SortableLayerTreeItem: FC<SortableLayerTreeItemProps> = ({ id, ...p
transform,
transition,
} = useSortable({
id,
id: layer.id,
animateLayoutChanges,
});
const style: CSSProperties = {
Expand All @@ -36,10 +33,10 @@ export const SortableLayerTreeItem: FC<SortableLayerTreeItemProps> = ({ id, ...p

return (
<LayerTreeItem
id={id}
ref={setNodeRef}
style={style}
disableInteraction={isSorting || isDragging || isOver}
layer={layer}
{...attributes}
{...listeners}
{...props}
Expand Down
1 change: 1 addition & 0 deletions src/components/editor/NavigationPanel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './NavigationPanel.tsx';

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 2a304d0

Please sign in to comment.