Skip to content

Commit 1e84df7

Browse files
committed
refactor: update data attribution
1 parent 490dadb commit 1e84df7

10 files changed

Lines changed: 91 additions & 6 deletions

File tree

web/src/classic/components/molecules/Visualizer/Widget/DataAttribution/ContentModal.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ const ContentModal: FC<ContentModalProps> = ({ visible, credits, publishedTheme,
3636
{credits?.map((credit, index) => (
3737
<ListItem key={index}>
3838
<ListMarker></ListMarker>
39-
{credit.creditUrl ? (
39+
{credit.builtinHtml ? (
40+
<CreditItem>
41+
<CreditText dangerouslySetInnerHTML={{ __html: credit.builtinHtml }} />
42+
</CreditItem>
43+
) : credit.creditUrl ? (
4044
<CreditItemLink
4145
target="_blank"
4246
href={credit.creditUrl}

web/src/classic/components/molecules/Visualizer/Widget/DataAttribution/index.tsx

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isEqual } from "lodash-es";
2-
import { FC, useEffect, useState } from "react";
2+
import { FC, useEffect, useMemo, useState } from "react";
33

44
import { useT } from "@reearth/services/i18n";
55
import { styled, usePublishTheme } from "@reearth/services/theme";
@@ -8,7 +8,7 @@ import { ComponentProps as WidgetProps } from "..";
88
import { Credits } from "../../Engine/ref";
99

1010
import ContentModal from "./ContentModal";
11-
import useCredits from "./useCredits";
11+
import useCredits, { ProcessedCredit } from "./useCredits";
1212

1313
export type Props = WidgetProps<DataAttributionWidgetProperty>;
1414

@@ -21,13 +21,39 @@ export type DataAttributionWidgetProperty = {
2121
}[];
2222
};
2323

24-
const DataAttribution: FC<Props> = ({ onGetCredits, sceneProperty, widget }) => {
24+
const DataAttribution: FC<Props> = ({
25+
onGetCredits,
26+
sceneProperty,
27+
widget,
28+
hasVisibleReearthBuildingsLayers,
29+
}) => {
2530
const t = useT();
2631
const [visible, setVisible] = useState(false);
2732
const [credits, setCredits] = useState<Credits>();
2833

2934
const publishedTheme = usePublishTheme(sceneProperty?.theme);
3035

36+
// Check for visible reearth-buildings tileset layers
37+
// This effect will run whenever hasVisibleReearthBuildingsLayers changes (layer added/removed/visibility changed)
38+
useEffect(() => {
39+
if (hasVisibleReearthBuildingsLayers) {
40+
console.log(
41+
"[Re:Earth] Visible reearth-buildings tileset layers detected",
42+
hasVisibleReearthBuildingsLayers,
43+
);
44+
}
45+
}, [hasVisibleReearthBuildingsLayers]);
46+
47+
const layerCredits: ProcessedCredit[] = useMemo(() => {
48+
if (!hasVisibleReearthBuildingsLayers) return [];
49+
return [
50+
{
51+
builtinHtml:
52+
'<a href="https://buildings.reearth.land/" target="_blank" rel="noopener">Re:Earth Buildings</a> — Buildings © <a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener">OpenStreetMap contributors</a>, <a href="https://overturemaps.org/" target="_blank" rel="noopener">Overture Maps Foundation</a> (ODbL)<br/> Terrain by <a href="https://terrain.reearth.land/" target="_blank" rel="noopener">Re:Earth Terrain</a> (Mapterhorn / EGM2008)',
53+
},
54+
];
55+
}, [hasVisibleReearthBuildingsLayers]);
56+
3157
useEffect(() => {
3258
let intervalId: NodeJS.Timeout | null = null;
3359

@@ -48,7 +74,14 @@ const DataAttribution: FC<Props> = ({ onGetCredits, sceneProperty, widget }) =>
4874
};
4975
}, [onGetCredits, credits]);
5076

51-
const { cesiumCredit, otherCredits } = useCredits({ credits, property: widget.property });
77+
const { cesiumCredit, otherCredits, googleCredit } = useCredits({
78+
credits,
79+
property: widget.property,
80+
});
81+
82+
const modalCredits = useMemo(() => {
83+
return [...(otherCredits ?? []), ...layerCredits];
84+
}, [layerCredits, otherCredits]);
5285

5386
return (
5487
<Wrapper>
@@ -57,11 +90,20 @@ const DataAttribution: FC<Props> = ({ onGetCredits, sceneProperty, widget }) =>
5790
<img src={cesiumCredit.logo} title={cesiumCredit.description} />
5891
</CesiumLink>
5992
)}
93+
{googleCredit && (
94+
<GoogleLink target="_blank" rel="noreferrer" aria-label={googleCredit.description}>
95+
<img
96+
src={googleCredit.logo}
97+
alt={googleCredit.description}
98+
title={googleCredit.description}
99+
/>
100+
</GoogleLink>
101+
)}
60102
<DataLink onClick={() => setVisible(true)}>{t("Data Attribution")}</DataLink>
61103
<ContentModal
62104
publishedTheme={publishedTheme}
63105
visible={visible}
64-
credits={otherCredits}
106+
credits={modalCredits}
65107
onClose={() => setVisible(false)}
66108
/>
67109
</Wrapper>
@@ -87,4 +129,8 @@ const DataLink = styled("div")(() => ({
87129
padding: 4,
88130
}));
89131

132+
const GoogleLink = styled("a")(() => ({
133+
height: 18,
134+
}));
135+
90136
export default DataAttribution;

web/src/classic/components/molecules/Visualizer/Widget/DataAttribution/useCredits.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ export type ProcessedCredit = {
1313
logo?: string;
1414
description?: string;
1515
creditUrl?: string;
16+
builtinHtml?: string; // For hardcoded credits like Re:Earth Buildings
1617
};
1718

1819
export default ({ credits, property }: Props) => {
1920
const [cesiumCredit, setCesiumCredit] = useState<ProcessedCredit | undefined>(undefined);
2021
const [otherCredits, setOtherCredits] = useState<ProcessedCredit[] | undefined>(undefined);
22+
const [googleCredit, setGoogleCredit] = useState<ProcessedCredit | undefined>(undefined);
2123

2224
useEffect(() => {
2325
if (credits) {
@@ -28,6 +30,14 @@ export default ({ credits, property }: Props) => {
2830
.map(processCredit)
2931
.filter(Boolean) as ProcessedCredit[];
3032
const screenCredits = credits.screen.map(processCredit).filter(Boolean) as ProcessedCredit[];
33+
let googleCredit = screenCredits.find(e => e.logo?.includes("google"));
34+
if (!googleCredit && credits.lightbox.some(c => c.html?.includes("Google"))) {
35+
googleCredit = {
36+
logo: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGIAAAASCAYAAACghwvPAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAs1JREFUeNrsWYGRhCAMtARLsARLoARLoARLsANKsARLoARKsARK4M+fcLOXCxHP+fPm/5lh5tQAIZtkA9c00FJK5taX9Ny2d0Nzcbvp0N+633rzW9ttcy7tt/liHU1W5MQc09Z3ZFqSs1eCEDbv35ShbwN54W8BIjeryMwk4y/ZnGbot3vHzwMRs7MJ6S9dAUTmhFVS7KCRukq5dkem2+SOAEFj+gNAJClFQfS/HYjcxhfGthDGCQAdBCMtgpwpkDF67ULvnAQEpc6VjRl39htgTMfmSqCDV9Z52CfoOJEOWReHjkfPEbPQ93d4YQreIXVHIASF2C2AFZmhsA0AQlTm8xwIMBwaR+UAmMvmihC+5fE9AsHW8cxZjBBpgWQirgFcvNLvcF9nBwjNKGPB6Bgh+BxBaQRxZSkhZC9l4EhArPCtZam2xAFo4KyDIU++8yST62kfFjmTGfmJZ9k+sejpWIRYNTWRgthnwStmIV1l41n4PQrpKoEhHiKElZtPQDBSNULIB4mzmIENyEYEr5CaFtj7wub6Bl9YL0eTA/vliLhXp4fIGjxwAiA0wpsqI25SSNgUgDCls45G2oKBF4m8mZGtkJpWAQi/o7/EqTFHhHkijvJBCL1Ri4gkRMSkRER/MiJWSpXZm9sDQHSYIgtAeM47sM/aiJgFgNzDOHagW8mAHS02MHJyNGbkaY3kPeZoxhEDbL7EEcglppIjkFeMVK2UgAAO6CqAaEuHPm4fgSMsRBLOEx4yAfP4qiuOA1WTJmdOVE1GkQ+1QOxFDnOmhVVnvlA1zehEharJS9HYACHHmks/MjInSekcIeVGz3M5gbGwuQLK80s/4eyxl2I9eq0ChIfo5/pH8HDHyuJJPCeUzxG+5iD67isMK4DjeL3/oZem7z2J/+BGZiXfp0+46/orQGgcEc7cg/0D8fofP1X5/sN0P/X/xZcAAwB8nuN904Y57wAAAABJRU5ErkJggg==",
37+
description: "Google Maps",
38+
};
39+
}
40+
setGoogleCredit(googleCredit);
3141
const widgetCredits =
3242
property?.default?.map(credit => ({
3343
logo: credit.logo,
@@ -42,6 +52,7 @@ export default ({ credits, property }: Props) => {
4252
return {
4353
cesiumCredit,
4454
otherCredits,
55+
googleCredit,
4556
};
4657
};
4758

web/src/classic/components/molecules/Visualizer/Widget/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type Props<PP = any, SP = any> = {
3131
onExtend?: (id: string, extended: boolean | undefined) => void;
3232
onVisibilityChange?: (widgetId: string, visible: boolean) => void;
3333
onGetCredits: () => Credits | undefined;
34+
hasVisibleReearthBuildingsLayers?: boolean;
3435
} & PluginCommonProps;
3536

3637
export type ComponentProps<PP = any, SP = any> = Omit<Props<PP, SP>, "widget"> & {

web/src/classic/components/molecules/Visualizer/WidgetAlignSystem/Area.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Props = {
3838
viewport?: Viewport;
3939
onWidgetAlignAreaSelect?: (widgetArea?: WidgetAreaState) => void;
4040
onGetCredits: () => Credits | undefined;
41+
hasVisibleReearthBuildingsLayers?: boolean;
4142
// note that layoutConstraint will be always undefined in published pages
4243
layoutConstraint?: { [w in string]: WidgetLayoutConstraint };
4344
} & PluginCommonProps;

web/src/classic/components/molecules/Visualizer/WidgetAlignSystem/MobileZone.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export type Props = {
2929
invisibleWidgetIDs?: string[];
3030
onWidgetAlignAreaSelect?: (widgetArea?: WidgetAreaState) => void;
3131
onGetCredits: () => Credits | undefined;
32+
hasVisibleReearthBuildingsLayers?: boolean;
3233
} & PluginCommonProps;
3334

3435
export default function MobileZone({

web/src/classic/components/molecules/Visualizer/WidgetAlignSystem/Zone.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type Props = {
2525
overrideSceneProperty?: (pluginId: string, property: any) => void;
2626
onWidgetAlignAreaSelect?: (widgetAreaState?: WidgetAreaState) => void;
2727
onGetCredits: () => Credits | undefined;
28+
hasVisibleReearthBuildingsLayers?: boolean;
2829
} & PluginCommonProps;
2930

3031
export default function Zone({

web/src/classic/components/molecules/Visualizer/WidgetAlignSystem/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export type Props = {
5454
onWidgetAlignAreaSelect?: (widgetArea?: WidgetAreaState) => void;
5555
onVisibilityChange?: (widgetId: string, visible: boolean) => void;
5656
onGetCredits: () => Credits | undefined;
57+
hasVisibleReearthBuildingsLayers?: boolean;
5758
} & PluginCommonProps;
5859

5960
const WidgetAlignSystem: React.FC<Props> = ({

web/src/classic/components/molecules/Visualizer/hooks.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,21 @@ export default ({
336336
return engineRef.current?.getCredits();
337337
}, [engineRef]);
338338

339+
const hasVisibleReearthBuildingsLayers = useMemo(() => {
340+
const flattenedLayers = layers?.flattenLayersRaw;
341+
if (!flattenedLayers) return false;
342+
343+
return flattenedLayers.some(layer => {
344+
// Check if layer is visible, type is tileset, and has reearth-buildings sourceType
345+
const isMatch =
346+
layer.isVisible &&
347+
layer.extensionId === "tileset" &&
348+
layer.property?.default?.sourceType === "reearth-buildings";
349+
350+
return isMatch;
351+
});
352+
}, [layers?.flattenLayersRaw]);
353+
339354
return {
340355
engineRef,
341356
wrapperRef,
@@ -372,6 +387,7 @@ export default ({
372387
handleLayerDrop,
373388
handleInfoboxMaskClick,
374389
getCredits,
390+
hasVisibleReearthBuildingsLayers,
375391
};
376392
};
377393

web/src/classic/components/molecules/Visualizer/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ export default function Visualizer({
149149
handleLayerDrop,
150150
handleInfoboxMaskClick,
151151
getCredits,
152+
hasVisibleReearthBuildingsLayers,
152153
} = useHooks({
153154
engineType: props.engine,
154155
rootLayerId,
@@ -204,6 +205,7 @@ export default function Visualizer({
204205
invisibleWidgetIDs={invisibleWidgetIDs}
205206
onVisibilityChange={onPluginWidgetVisibilityChange}
206207
onGetCredits={getCredits}
208+
hasVisibleReearthBuildingsLayers={hasVisibleReearthBuildingsLayers}
207209
/>
208210
)}
209211
<Engine
@@ -261,6 +263,7 @@ export default function Visualizer({
261263
pluginBaseUrl={pluginBaseUrl}
262264
viewport={viewport}
263265
onGetCredits={getCredits}
266+
hasVisibleReearthBuildingsLayers={hasVisibleReearthBuildingsLayers}
264267
/>
265268
))}
266269
</Engine>

0 commit comments

Comments
 (0)