Skip to content

Commit

Permalink
chore(web): add page name tag to indicator and fix some small bugs (#841
Browse files Browse the repository at this point in the history
)
  • Loading branch information
KaWaite authored Nov 29, 2023
1 parent 68c18da commit 968b6b4
Show file tree
Hide file tree
Showing 15 changed files with 193 additions and 105 deletions.
9 changes: 4 additions & 5 deletions server/pkg/builtin/manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ extensions:
defaultValue: 3d
choices:
- key: 3d
label: Scene 3D
label: 3D
- key: 2d
label: Scene 2D
label: 2D
- key: columbus
label: Columbus View
label: 2.5D (Columbus View)
- id: ion
type: string
title: Cesium Ion API access token
Expand Down Expand Up @@ -2323,11 +2323,10 @@ extensions:
ui: color
- id: padding
type: spacing
title: Spacing settings
title: Padding
ui: padding
min: 0
max: 100
defaultValue: { top: 0, bottom: 0, left: 0, right: 0 }
- id: cameraAnimation
title: Camera Animation
fields:
Expand Down
2 changes: 2 additions & 0 deletions server/pkg/builtin/manifest_ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,8 @@ extensions:
title: タイトル
color:
title:
padding:
title: 余白
cameraAnimation:
title: カメラアニメーション
fields:
Expand Down
3 changes: 2 additions & 1 deletion web/src/beta/components/Popover/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function usePopover({
placement = "bottom",
modal,
offset: offsetProps,
shift: shiftProps,
open: controlledOpen,
onOpenChange: setControlledOpen,
}: PopoverOptions = {}) {
Expand All @@ -38,7 +39,7 @@ export default function usePopover({
fallbackAxisSideDirection: "end",
padding: 4,
}),
shift({ padding: 4 }),
shift(shiftProps ?? { padding: 4 }),
],
});

Expand Down
116 changes: 61 additions & 55 deletions web/src/beta/components/Popover/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import {
FloatingFocusManager,
useTransitionStyles,
} from "@floating-ui/react";
import * as React from "react";
import {
forwardRef,
isValidElement,
cloneElement,
MutableRefObject,
type ButtonHTMLAttributes,
type HTMLProps,
type ReactNode,
} from "react";

import { PopoverContext, usePopoverContext } from "@reearth/beta/components/Popover/context";
import { useTheme } from "@reearth/services/theme";
Expand All @@ -18,27 +26,27 @@ export function Provider({
modal = false,
...restOptions
}: {
children: React.ReactNode;
children: ReactNode;
} & PopoverOptions) {
const popover = usePopover({ modal, ...restOptions });
return <PopoverContext.Provider value={popover}>{children}</PopoverContext.Provider>;
}

type TriggerProps = {
className?: string;
children: React.ReactNode;
children: ReactNode;
asChild?: boolean;
};

export const Trigger = React.forwardRef<HTMLElement, React.HTMLProps<HTMLElement> & TriggerProps>(
export const Trigger = forwardRef<HTMLElement, HTMLProps<HTMLElement> & TriggerProps>(
function Trigger({ children, asChild = false, className, ...props }, propRef) {
const context = usePopoverContext();
const childrenRef = (children as any).ref;

Check warning on line 44 in web/src/beta/components/Popover/index.tsx

View workflow job for this annotation

GitHub Actions / ci-web / ci

Unexpected any. Specify a different type
const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef]);

// `asChild` allows the user to pass any element as the anchor
if (asChild && React.isValidElement(children)) {
return React.cloneElement(
if (asChild && isValidElement(children)) {
return cloneElement(
children,
context.getReferenceProps({
ref,
Expand Down Expand Up @@ -68,55 +76,53 @@ type ContentProps = {
attachToRoot?: boolean;
};

export const Content = React.forwardRef<
HTMLDivElement,
React.HTMLProps<HTMLDivElement> & ContentProps
>(function Content({ style, className, attachToRoot = false, ...props }, propRef) {
const { context: floatingContext, ...context } = usePopoverContext();
const theme = useTheme();
const ref = useMergeRefs([context.refs.setFloating, propRef]);
const { isMounted, styles: transitionStyles } = useTransitionStyles(floatingContext, {
duration: 50,
});
export const Content = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement> & ContentProps>(
function Content({ style, className, attachToRoot = false, ...props }, propRef) {
const { context: floatingContext, ...context } = usePopoverContext();
const theme = useTheme();
const ref = useMergeRefs([context.refs.setFloating, propRef]);
const { isMounted, styles: transitionStyles } = useTransitionStyles(floatingContext, {
duration: 50,
});

if (!isMounted) return null;
if (!isMounted) return null;

return (
<FloatingPortal
// whether to render this inside the Trigger or outside the main div
root={attachToRoot ? (context.refs.domReference as React.MutableRefObject<null>) : null}>
<FloatingFocusManager context={floatingContext} modal={context.modal} initialFocus={-1}>
<div
ref={ref}
className={className}
style={{
...context.floatingStyles,
...transitionStyles,
...style,
zIndex: theme.zIndexes.editor.popover,
}}
{...context.getFloatingProps(props)}>
{props.children}
</div>
</FloatingFocusManager>
</FloatingPortal>
);
});
return (
<FloatingPortal
// whether to render this inside the Trigger or outside the main div
root={attachToRoot ? (context.refs.domReference as MutableRefObject<null>) : null}>
<FloatingFocusManager context={floatingContext} modal={context.modal} initialFocus={-1}>
<div
ref={ref}
className={className}
style={{
...context.floatingStyles,
...transitionStyles,
...style,
zIndex: theme.zIndexes.editor.popover,
}}
{...context.getFloatingProps(props)}>
{props.children}
</div>
</FloatingFocusManager>
</FloatingPortal>
);
},
);

export const Close = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(function PopoverClose(props, ref) {
const { setOpen } = usePopoverContext();
return (
<button
type="button"
ref={ref}
{...props}
onClick={event => {
props.onClick?.(event);
setOpen(false);
}}
/>
);
});
export const Close = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
function PopoverClose(props, ref) {
const { setOpen } = usePopoverContext();
return (
<button
type="button"
ref={ref}
{...props}
onClick={event => {
props.onClick?.(event);
setOpen(false);
}}
/>
);
},
);
3 changes: 2 additions & 1 deletion web/src/beta/components/Popover/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Placement, OffsetOptions } from "@floating-ui/react";
import { Placement, OffsetOptions, ShiftOptions } from "@floating-ui/react";

export type PopoverOptions = {
initialOpen?: boolean;
placement?: Placement;
modal?: boolean; // @see https://floating-ui.com/docs/floatingfocusmanager#modal
open?: boolean;
offset?: OffsetOptions; // @see https://floating-ui.com/docs/offset
shift?: ShiftOptions;
onOpenChange?: (open: boolean) => void;
};
9 changes: 5 additions & 4 deletions web/src/beta/components/SidePanelSectionField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ const SidePanelSectionField: React.FC<{
className?: string;
title?: string;
startCollapsed?: boolean;
gap?: number;
children?: ReactNode;
}> = ({ className, title, startCollapsed, children }) => {
}> = ({ className, title, startCollapsed, gap, children }) => {
const theme = useTheme();
const [opened, setOpened] = useState<boolean>();

Expand All @@ -28,7 +29,7 @@ const SidePanelSectionField: React.FC<{
<ArrowIcon icon="arrowToggle" size={12} color={theme.content.main} opened={opened} />
</Header>
)}
{opened && children && <Content>{children}</Content>}
{opened && children && <Content gap={gap}>{children}</Content>}
</Field>
);
};
Expand All @@ -52,11 +53,11 @@ const ArrowIcon = styled(Icon)<{ opened?: boolean }>`
transition: all 0.2s;
`;

const Content = styled.div`
const Content = styled.div<{ gap?: number }>`
padding: 8px;
display: flex;
flex-direction: column;
gap: 16px;
gap: ${({ gap }) => (gap ?? 16) + "px"} 16px;
`;

export default SidePanelSectionField;
2 changes: 1 addition & 1 deletion web/src/beta/components/fields/ListField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const ListField: React.FC<Props> = ({
onClick={addItem}
icon="plus"
buttonType="secondary"
text={t("Add Item")}
text={t("Add")}
size="medium"
/>
</ButtonGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const PropertyList: React.FC<Props> = ({
onClick={handleAddPropertyItem}
icon="plus"
buttonType="secondary"
text={t("Add Item")}
text={t("Add")}
size="medium"
/>
</ButtonGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const GroupSectionField: React.FC<GroupSectionFieldProps> = ({

return (
<>
<StyledSidePanelSectionField title={t("Scene")} startCollapsed>
<StyledSidePanelSectionField title={t("Scene")} startCollapsed gap={0}>
{[...new Set(scene?.property?.schema?.groups.map(({ collection }) => collection))].map(
(collection, index) =>
collection && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useCallback, useMemo, useState } from "react";

import * as Popover from "@reearth/beta/components/Popover";
import Text from "@reearth/beta/components/Text";
import { styled } from "@reearth/services/theme";

type Props = {
title?: string;
pageNumber: number;
currentPageNumber: number;
onPageChange: (page: number) => void;
};

const IndicatorSection: React.FC<Props> = ({
pageNumber,
currentPageNumber,
title,
onPageChange,
}) => {
const [isHovered, setIsHovered] = useState(false);

const handleMouseEnter = useCallback(() => setIsHovered(true), []);
const handleMouseOut = useCallback(() => setIsHovered(false), []);

const handleClick = useCallback(() => {
onPageChange(pageNumber);
setIsHovered(false);
}, [pageNumber, onPageChange]);

const isHighlighted = useMemo(
() => pageNumber <= currentPageNumber,
[currentPageNumber, pageNumber],
);

// const isLast = useMemo(() => pageNumber === totalPages, [pageNumber, totalPages]);

return (
<Wrapper onClick={handleClick} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseOut}>
<Popover.Provider open={isHovered} placement="bottom" offset={0} shift={{ padding: 0 }}>
<Popover.Trigger asChild>
<Indicator highlighted={isHighlighted} />
</Popover.Trigger>
<Popover.Content attachToRoot>
<PageNameWrapper isHighlighted={isHighlighted}>
<StyledText size="footnote" customColor>
{title}
</StyledText>
</PageNameWrapper>
</Popover.Content>
</Popover.Provider>
</Wrapper>
);
};

export default IndicatorSection;

const Wrapper = styled.div`
flex: 1;
cursor: pointer;
color: ${({ theme }) => theme.content.strong};
:not(:first-of-type) {
border-left: 1px solid #ffffff;
}
`;

const Indicator = styled.div<{ highlighted: boolean }>`
height: 100%;
${({ highlighted }) =>
highlighted &&
`
background-color: #4589ff;
width: 100%;
`}
`;

const PageNameWrapper = styled.div<{ isHighlighted: boolean }>`
background-color: #78a9ff;
padding: 4px 8px;
${({ isHighlighted }) => isHighlighted && "background-color: #4589ff;"}
max-width: 255px;
`;

const StyledText = styled(Text)`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
Loading

0 comments on commit 968b6b4

Please sign in to comment.