Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(web): layer style editor node support typography #1168

Merged
merged 4 commits into from
Oct 4, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import Field from "./Field";

type Props = {
conditions?: StyleCondition[];
field: AppearanceField;
field?: AppearanceField;
valueOptions?: { value: string; label: string }[];
onUpdate: (value: StyleCondition[]) => void;
disabled?: boolean;
onUpdate?: (value: StyleCondition[]) => void;
};

export const styleConditionOperators: StyleConditionOperator[] = [
Expand Down Expand Up @@ -54,6 +55,7 @@ const ConditionsTab: FC<Props> = ({
conditions,
field,
valueOptions,
disabled,
onUpdate
}) => {
const handleItemDrop = useCallback(
Expand All @@ -69,7 +71,7 @@ const ConditionsTab: FC<Props> = ({
const [draggedItem] = newConditions.splice(draggedIndex, 1);
newConditions.splice(targetIndex, 0, draggedItem);

onUpdate(newConditions);
onUpdate?.(newConditions);
},
[conditions, onUpdate]
);
Expand All @@ -89,7 +91,7 @@ const ConditionsTab: FC<Props> = ({
const t = useT();

const createCondition = useCallback(() => {
onUpdate([
onUpdate?.([
...(conditions ?? []),
{
variable: "",
Expand All @@ -107,7 +109,7 @@ const ConditionsTab: FC<Props> = ({
...newConditions[idx],
[key]: value
};
onUpdate(newConditions);
onUpdate?.(newConditions);
},
[conditions, onUpdate]
);
Expand All @@ -116,7 +118,7 @@ const ConditionsTab: FC<Props> = ({
(idx: number) => {
const newConditions = conditions ? [...conditions] : [];
newConditions.splice(idx, 1);
onUpdate(newConditions);
onUpdate?.(newConditions);
},
[conditions, onUpdate]
);
Expand All @@ -128,7 +130,7 @@ const ConditionsTab: FC<Props> = ({
...newConditions[idx],
applyValue: value
};
onUpdate(newConditions);
onUpdate?.(newConditions);
},
[conditions, onUpdate]
);
Expand Down Expand Up @@ -206,8 +208,16 @@ const ConditionsTab: FC<Props> = ({
]
);

return (
<Wrapper>
return disabled ? (
<InfoWrapper>
<Typography size="body" color="weak">
{t(
"UI doesn't support conditions on this property, please edit code directly."
)}
</Typography>
</InfoWrapper>
) : (
<ConditionsWrapper>
<IconButtonWrapper>
<IconButton
key="add"
Expand All @@ -225,19 +235,23 @@ const ConditionsTab: FC<Props> = ({
onMoveEnd={handleMoveEnd}
/>
)}
</Wrapper>
</ConditionsWrapper>
);
};

export default ConditionsTab;

const Wrapper = styled("div")(({ theme }) => ({
const ConditionsWrapper = styled("div")(({ theme }) => ({
display: "flex",
flexDirection: "column",
gap: theme.spacing.smallest,
paddingBottom: theme.spacing.smallest
}));

const InfoWrapper = styled("div")(({ theme }) => ({
padding: theme.spacing.small
}));

const IconButtonWrapper = styled("div")(() => ({
display: "flex",
justifyContent: "flex-end",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import { TextInput } from "@reearth/beta/lib/reearth-ui";
import { TextInput, Typography } from "@reearth/beta/lib/reearth-ui";
import { useT } from "@reearth/services/i18n";
import { styled } from "@reearth/services/theme";
import { FC } from "react";

type Props = {
expression: string;
onUpdate: (expression: string) => void;
expression?: string;
disabled?: boolean;
onUpdate?: (expression: string) => void;
};

const ExpressionTab: FC<Props> = ({ expression, onUpdate }) => {
const ExpressionTab: FC<Props> = ({ expression, disabled, onUpdate }) => {
const t = useT();

return (
<Wrapper>
<Icon>=</Icon>
<TextInput value={expression ?? ""} onBlur={onUpdate} />
{disabled ? (
<InfoWrapper>
<Typography size="body" color="weak">
{t(
"UI doesn't support expression on this property, please edit code directly."
)}
</Typography>
</InfoWrapper>
) : (
<>
<Icon>=</Icon>
<TextInput value={expression ?? ""} onBlur={onUpdate} />
</>
)}
</Wrapper>
);
};
Expand All @@ -24,6 +40,10 @@ const Wrapper = styled("div")(({ theme }) => ({
alignItems: "center"
}));

const InfoWrapper = styled("div")(({ theme }) => ({
padding: theme.spacing.small
}));

const Icon = styled("div")(({ theme }) => ({
color: theme.content.weak
}));
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Selector } from "@reearth/beta/lib/reearth-ui";
import { FC } from "react";

const booleanOptions = [
{ value: "true", label: "true" },
{ value: "false", label: "false" }
];

type Props = {
value: boolean | undefined;
onChange: (value: boolean | undefined) => void;
};

const BooleanSelectorInput: FC<Props> = ({ value, onChange }) => {
return (
<Selector
value={value === true ? "true" : value === false ? "false" : ""}
options={booleanOptions}
onChange={(v) =>
onChange(v === "true" ? true : v === "false" ? false : undefined)
}
/>
);
};

export default BooleanSelectorInput;
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import {
ColorInput,
NumberInput,
Selector
} from "@reearth/beta/lib/reearth-ui";
import { useT } from "@reearth/services/i18n";
import { styled } from "@reearth/services/theme";
import { FC, ReactNode } from "react";

import { Typography } from "../../types";

import BooleanSelectorField from "./BooleanSelectorInput";

const fontFamilyOptions = [
{ value: "Arial", label: "Arial" },
{ value: "Comic Sans MS", label: "Comic Sans MS" },
{ value: "Courier New", label: "Courier New" },
{ value: "Georgia", label: "Georgia" },
{ value: "Tahoma", label: "Tahoma" },
{ value: "Times New Roman", label: "Times New Roman" },
{ value: "Trebuchet MS", label: "Trebuchet MS" },
{ value: "Verdana", label: "Verdana" },
{ value: "YuGothic", label: "游ゴシック" }
];

const fontWeightOptions = [
{ value: "lighter", label: "lighter" },
{ value: "normal", label: "normal" },
{ value: "bold", label: "bold" },
{ value: "bolder", label: "bolder" }
];
airslice marked this conversation as resolved.
Show resolved Hide resolved

type Props = {
value: Typography | undefined;
onChange: (value: Typography | undefined) => void;
};

const TypographyInput: FC<Props> = ({ value, onChange }) => {
const t = useT();
return (
<Wrapper>
<PropertyItem title={t("font family")}>
<Selector
options={fontFamilyOptions}
value={value?.fontFamily}
onChange={(v) => onChange?.({ ...value, fontFamily: v as string })}
/>
</PropertyItem>
<PropertyItem title={t("font size")}>
<NumberInput
value={value?.fontSize}
onChange={(v) => onChange?.({ ...value, fontSize: v })}
/>
</PropertyItem>
<PropertyItem title={t("font weight")}>
<Selector
options={fontWeightOptions}
value={value?.fontWeight}
onChange={(v) =>
onChange?.({
...value,
fontWeight: v as "lighter" | "normal" | "bold" | "bolder"
})
}
/>
</PropertyItem>
<PropertyItem title={t("font color")}>
<ColorInput
value={value?.color as string}
onChange={(v) => onChange?.({ ...value, color: v })}
/>
</PropertyItem>
<PropertyItem title={t("italic")}>
<BooleanSelectorField
value={value?.italic}
onChange={(v) => onChange?.({ ...value, italic: v })}
/>
</PropertyItem>
<PropertyItem title={t("underline")}>
<BooleanSelectorField
value={value?.underline}
onChange={(v) => onChange?.({ ...value, underline: v })}
/>
</PropertyItem>
</Wrapper>
);
};

export default TypographyInput;

const Wrapper = styled("div")(({ theme }) => ({
display: "flex",
flexDirection: "column",
gap: theme.spacing.smallest,
width: "100%"
}));

const PropertyItem: FC<{ title: string; children?: ReactNode }> = ({
title,
children
}) => {
return (
<PropertyItemWrapper>
<Title>{title}</Title>
<Content>{children}</Content>
</PropertyItemWrapper>
);
};

const PropertyItemWrapper = styled("div")(({ theme }) => ({
display: "flex",
gap: theme.spacing.small,
width: "100%",
alignItems: "center"
}));

const Title = styled("div")(({ theme }) => ({
color: theme.content.main,
fontSize: theme.fonts.sizes.body,
fontWeight: theme.fonts.weight.regular,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
width: "50%",
flexGrow: 0
}));

const Content = styled("div")(() => ({
width: "50%",
flexGrow: 0
}));
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,56 @@ import {
ColorInput,
NumberInput,
Selector,
Switcher,
TextInput
} from "@reearth/beta/lib/reearth-ui";
import { FC } from "react";

import { AppearanceField, StyleSimpleValue } from "../types";
import { AppearanceField, StyleSimpleValue, Typography } from "../../types";

type Props = {
field: AppearanceField;
import BooleanSelectorInput from "./BooleanSelectorInput";
import TypographyInput from "./TypographyInput";

type FieldProps = {
field?: AppearanceField;
value: StyleSimpleValue;
options?: { value: string; label: string }[];
onUpdate: (value: StyleSimpleValue) => void;
};

const fieldComponents = {
switch: (props: Props) => (
<Switcher value={props.value as boolean} onChange={props.onUpdate} />
switch: (props: FieldProps) => (
<BooleanSelectorInput
value={props.value as boolean}
onChange={props.onUpdate}
/>
),
number: (props: Props) => (
number: (props: FieldProps) => (
<NumberInput value={props.value as number} onChange={props.onUpdate} />
),
text: (props: Props) => (
text: (props: FieldProps) => (
<TextInput value={props.value as string} onChange={props.onUpdate} />
),
color: (props: Props) => (
color: (props: FieldProps) => (
<ColorInput value={props.value as string} onChange={props.onUpdate} />
),
select: (props: Props) =>
select: (props: FieldProps) =>
props.options ? (
<Selector
value={props.value as string}
options={props.options}
onChange={(v) => props.onUpdate(v as string)}
/>
) : null
) : null,
typography: (props: FieldProps) => (
<TypographyInput
value={props.value as Typography}
onChange={props.onUpdate}
/>
)
};

const Field: FC<Props> = (props) => {
const Field: FC<FieldProps> = (props) => {
if (!props.field) return null;
const FieldComponent = fieldComponents[props.field];
return FieldComponent ? <FieldComponent {...props} /> : null;
};
Expand Down
Loading
Loading