Skip to content

Commit

Permalink
FeaturePanel: refactor FeaturedTags to use regexps (#939)
Browse files Browse the repository at this point in the history
  • Loading branch information
zbycz authored Feb 6, 2025
1 parent 9979fce commit 0aebc65
Show file tree
Hide file tree
Showing 21 changed files with 188 additions and 179 deletions.
3 changes: 2 additions & 1 deletion src/components/FeaturePanel/Climbing/ClimbingGradesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
Typography,
} from '@mui/material';

import { GRADE_SYSTEMS, GRADE_TABLE } from './utils/grades/gradeData';
import { GRADE_TABLE } from './utils/grades/gradeData';
import CloseIcon from '@mui/icons-material/Close';
import zip from 'lodash/zip';
import { useTheme } from '@emotion/react';
Expand All @@ -30,6 +30,7 @@ import { getUrlOsmId } from '../../../services/helpers';
import { t } from '../../../services/intl';
import { useUserSettingsContext } from '../../utils/UserSettingsContext';
import { isMobileDevice } from '../../helpers';
import { GRADE_SYSTEMS } from '../../../services/tagging/climbing';

export const ClimbingGradesTable = () => {
const [clickedItem, setClickedItem] = React.useState<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { getHumanPoiType } from '../../../helpers/featureLabel';
import {
findOrConvertRouteGrade,
getDifficulties,
getGradeSystemName,
} from './utils/grades/routeGrade';
import { useUserSettingsContext } from '../../utils/UserSettingsContext';
import { getGradeSystemName } from '../../../services/tagging/climbing';

const generateScriptContent = (feature, userSettings) => {
const isClimbingArea = feature.tags.climbing === 'area';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import React from 'react';
import styled from '@emotion/styled';
import {
findOrConvertRouteGrade,
getGradeSystemName,
} from './utils/grades/routeGrade';
import { findOrConvertRouteGrade } from './utils/grades/routeGrade';
import { getGradeSystemName } from '../../../services/tagging/climbing';
import { useUserSettingsContext } from '../../utils/UserSettingsContext';
import { RouteDifficulty } from './types';
import { RouteDifficultyBadge } from './RouteDifficultyBadge';
Expand Down
2 changes: 1 addition & 1 deletion src/components/FeaturePanel/Climbing/GradeSystemSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import styled from '@emotion/styled';
import { GRADE_SYSTEMS, GradeSystem } from './utils/grades/gradeData';
import { GRADE_SYSTEMS, GradeSystem } from '../../../services/tagging/climbing';
import Link from 'next/link';

type Props = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { RouteDifficulty } from './types';
import { GradeSystemSelect } from './GradeSystemSelect';
import { useClimbingContext } from './contexts/ClimbingContext';
import { convertGrade } from './utils/grades/routeGrade';
import { GradeSystem } from './utils/grades/gradeData';

import { GradeSystem } from '../../../services/tagging/climbing';

const Flex = styled.div`
display: flex;
Expand Down
2 changes: 1 addition & 1 deletion src/components/FeaturePanel/Climbing/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GradeSystem } from './utils/grades/gradeData';
import { Feature, FeatureTags } from '../../../services/types';
import { GradeSystem } from '../../../services/tagging/climbing';

export type PointType = 'anchor' | 'bolt' | 'piton' | 'sling' | 'unfinished';

Expand Down
71 changes: 7 additions & 64 deletions src/components/FeaturePanel/Climbing/utils/grades/gradeData.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,11 @@
// The order of this array must be the same as in CSV below
export const GRADE_SYSTEMS = [
{
key: 'uiaa',
name: 'UIAA',
description:
'Grade system used by the International Climbing and Mountaineering Federation.',
},
{
key: 'british_traditional',
name: 'British technical',
description: 'The British grading system for traditional climbs.',
},
{
key: 'british_adjectival',
name: 'British Adjectival',
description:
'The Adjectival British Scale or the overall assessment scale.',
},
{
key: 'french_british',
name: 'French British',
description:
'Sport climbing in Britain and Ireland uses the French grading system.',
},
{
key: 'french',
name: 'French',
description:
'The French numerical system (Fontainebleau scale) rates a climb according to the overall technical difficulty and strenuousness of the route.',
},
{
key: 'saxon',
name: 'Saxon',
description:
'The Saxon grading system was developed in the beginning of the 20th century for the formidable Saxon Switzerland climbing region.',
},
{ key: 'nordic', name: 'Nordic', description: 'The Nordic grading system.' },
{
key: 'yds_class',
name: 'YDS',
description:
'The Yosemite Decimal System of grading routes of hikes and climbs developed for the Sierra Nevada range.',
},
{
key: 'hueco',
name: 'V grade',
description:
'V scale grading system, created by John Sherman, which is the most widely used system in North America.',
},
{
key: 'ice',
name: 'WI',
description: 'Waterfall ice rating system as used in the Canadian Rockies.',
},
{
key: 'mixed',
name: 'Mixed',
description:
'Mixed climbing has its own grading scale that roughly follows the WI rating system.',
},
];
import {
GRADE_SYSTEMS,
GradeSystem,
} from '../../../../../services/tagging/climbing';

export type GradeSystem = (typeof GRADE_SYSTEMS)[number]['key'];
export type GradeTable = Record<GradeSystem, Array<string>>;
type GradeTable = Record<GradeSystem, Array<string>>;

// The order of the GRADE_SYSTEMS array must be the same as CSV below !!

// Source of this table is: https://wiki.openstreetmap.org/wiki/Climbing#Grading
// UIAA French/British Nordic WI
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { RouteDifficulty } from '../../types';
import {
csvToArray,
GRADE_SYSTEMS,
GRADE_TABLE,
gradeColors,
GradeSystem,
gradeTableString,
} from './gradeData';
import { GradeSystem } from '../../../../../services/tagging/climbing';
import { FeatureTags } from '../../../../../services/types';

export const exportGradeDataToWikiTable = () => {
Expand Down Expand Up @@ -99,9 +98,6 @@ export const getDifficultyColor = (routeDifficulty, theme) => {
return gradeColors[uiaaGrade]?.[mode] || DEFAULT_COLOR;
};

export const getGradeSystemName = (gradeSystemKey: GradeSystem) =>
GRADE_SYSTEMS.find((item) => item.key === gradeSystemKey)?.name;

export const findOrConvertRouteGrade = (
routeDifficulties: RouteDifficulty[],
selectedRouteSystem: string,
Expand Down
26 changes: 7 additions & 19 deletions src/components/FeaturePanel/FeaturePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,29 +52,17 @@ export const FeaturePanel = ({ headingRef }: FeaturePanelProps) => {
return null;
}

// ------------------------------------------------------------------------
// Different components are shown for different types of features
// Conditional components should have if(feature.tags.xxx) check at the beginning
// All components should have margin-bottoms to accommodate missing parts
const isClimbingCrag = tags.climbing === 'crag';
const isClimbing = climbingTagValues.includes(feature.tags.climbing);

const ClimbingDescription = () => {
if (!isClimbing || !feature.tags.description) {
return null;
}

return (
<FeaturedTag
key={'description'}
k={'description'}
v={feature.tags.description}
/>
);
};
// ------------------------------------------------------------------------

const movePropertiesBelowMembers = tags.climbing === 'crag';
const PropertiesComponent = () => (
<Properties showTags={showTagsTable} key={getReactKey(feature)} />
);

return (
<>
<PanelContent>
Expand All @@ -90,7 +78,7 @@ export const FeaturePanel = ({ headingRef }: FeaturePanelProps) => {

<OsmError />
<TestApiWarning />
<ClimbingDescription />
<FeaturedTag k="description" renderer="DescriptionRenderer" />
</PanelSidePadding>

<Flex>
Expand All @@ -103,11 +91,11 @@ export const FeaturePanel = ({ headingRef }: FeaturePanelProps) => {
</Box>

<PanelSidePadding>
{!isClimbingCrag && <PropertiesComponent />}
{!movePropertiesBelowMembers && <PropertiesComponent />}
<RouteDistributionInPanel />
{!isPublictransportRoute(feature) && <MemberFeatures />}
{advanced && <Members />}
{isClimbingCrag && <PropertiesComponent />}
{movePropertiesBelowMembers && <PropertiesComponent />}
<PublicTransport />
<Runways />
<Sockets />
Expand Down
67 changes: 33 additions & 34 deletions src/components/FeaturePanel/FeaturedTag.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import React from 'react';
import styled from '@emotion/styled';

import WebsiteRenderer from './renderers/WebsiteRenderer';
import OpeningHoursRenderer from './renderers/OpeningHoursRenderer';
import PhoneRenderer from './renderers/PhoneRenderer';
import { WebsiteRenderer } from './renderers/WebsiteRenderer';
import { OpeningHoursRenderer } from './renderers/OpeningHoursRenderer';
import { PhoneRenderer } from './renderers/PhoneRenderer';
import { InlineEditButton } from './helpers/InlineEditButton';
import { FoodHygieneRatingSchemeRenderer } from './renderers/FoodHygieneRatingScheme';
import { WikipediaRenderer } from './renderers/WikipediaRenderer';
import { WikidataRenderer } from './renderers/WikidataRenderer';
import { isDesktopResolution } from '../helpers';
import { ClimbingRenderer } from './renderers/ClimbingRenderer';
import { gradeSystemKeys } from './Climbing/utils/grades/gradeSystem';
import { ClimbingGradeRenderer } from './renderers/ClimbingGradeRenderer';
import { nl2br } from '../utils/nl2br';
import { FeaturedKeyRenderer } from '../../services/tagging/featuredKeys';
import { useFeatureContext } from '../utils/FeatureContext';

const Wrapper = styled.div`
position: relative;
Expand Down Expand Up @@ -43,45 +43,44 @@ const Value = styled.div`
}
`;

type Renderers = {
[key: string]: React.FC<{ k: string; v: string }>;
};

const DefaultRenderer = ({ v }) => <>{nl2br(v)}</>;

const climbingRenderers = gradeSystemKeys.reduce(
(acc, gradeSystemKey) => ({
...acc,
[gradeSystemKey]: ClimbingRenderer,
}),
{},
);
type RendererComponents = {
[key in FeaturedKeyRenderer]: React.FC<{ k: string; v: string }>;
};

const components: RendererComponents = {
WebsiteRenderer: WebsiteRenderer,
PhoneRenderer: PhoneRenderer,
OpeningHoursRenderer: OpeningHoursRenderer,
FoodHygieneRatingSchemeRenderer: FoodHygieneRatingSchemeRenderer,
WikipediaRenderer: WikipediaRenderer,
WikidataRenderer: WikidataRenderer,
ClimbingGradeRenderer: ClimbingGradeRenderer,
DescriptionRenderer: DefaultRenderer,
NullRenderer: null,
};

const renderers: Renderers = {
// also update in schema – getFeaturedTags()
website: WebsiteRenderer,
'website:2': WebsiteRenderer,
'contact:website': WebsiteRenderer,
url: WebsiteRenderer,
phone: PhoneRenderer,
'contact:phone': PhoneRenderer,
'contact:mobile': PhoneRenderer,
opening_hours: OpeningHoursRenderer,
'fhrs:id': FoodHygieneRatingSchemeRenderer,
wikipedia: WikipediaRenderer,
wikidata: WikidataRenderer,
...climbingRenderers,
type Props = {
k: string;
renderer: FeaturedKeyRenderer;
};

export const FeaturedTag = ({ k, v }) => {
const Renderer = renderers[k] || DefaultRenderer;
export const FeaturedTag = ({ k, renderer }: Props) => {
const { feature } = useFeatureContext();
const value = feature.tags[k];

const Renderer = components[renderer];
if (!Renderer || !value) {
return null;
}

return (
<Wrapper>
<InlineEditButton k={k} />

<Value>
<Renderer k={k} v={v} />
<Renderer k={k} v={value} />
</Value>
</Wrapper>
);
Expand Down
26 changes: 18 additions & 8 deletions src/components/FeaturePanel/FeaturedTags.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import React from 'react';
import styled from '@emotion/styled';
import { FeaturedTag } from './FeaturedTag';
import { climbingTagValues } from './Climbing/utils/climbingTagValues';
import { useFeatureContext } from '../utils/FeatureContext';
import { FEATURED_KEYS } from '../../services/tagging/featuredKeys';

const Spacer = styled.div`
padding-bottom: 10px;
`;

export const FeaturedTags = ({ featuredTags }) => {
export const FeaturedTags = () => {
const { feature } = useFeatureContext();
if (!featuredTags.length) return null;
const isClimbing = climbingTagValues.includes(feature.tags.climbing);

const keys =
feature.schema?.featuredTags
.map(([k, v]) => ({
k,
v,
featuredKey: FEATURED_KEYS.find(({ matcher }) => matcher.test(k)),
}))
.filter(({ featuredKey, v }) => featuredKey && v) ?? [];

if (!keys.length) {
return null;
}

return (
<>
{featuredTags.map(([k, v]) => {
if (isClimbing && k === 'description') return null;

return <FeaturedTag key={k} k={k} v={v} />;
{keys.map(({ k, v, featuredKey }) => {
return <FeaturedTag key={k} k={k} renderer={featuredKey.renderer} />;
})}
<Spacer />
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/FeaturePanel/Properties/Properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export const Properties = ({ showTags }) => {

{!showTags && (
<ErrorBoundary key={getReactKey(feature)} fallback={<OnlyTagsTable />}>
<FeaturedTags featuredTags={feature.schema?.featuredTags} />
<FeaturedTags />
<IdSchemaFields />
</ErrorBoundary>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { RouteDifficultyBadge } from '../Climbing/RouteDifficultyBadge';
import {
getDifficulties,
getGradeSystemFromOsmTag,
getGradeSystemName,
} from '../Climbing/utils/grades/routeGrade';
import { getGradeSystemName } from '../../../services/tagging/climbing';
import { t } from '../../../services/intl';

const Container = styled.div`
display: flex;
gap: 8px;
`;

export const ClimbingRenderer = ({ k, v }) => {
export const ClimbingGradeRenderer = ({ k, v }) => {
const routeDifficulties = getDifficulties({ [k]: v });
const gradeSystemName = getGradeSystemName(getGradeSystemFromOsmTag(k));
return (
Expand Down
Loading

0 comments on commit 0aebc65

Please sign in to comment.