Skip to content

Commit

Permalink
Merge pull request #33 from plezanje-net/crags
Browse files Browse the repository at this point in the history
Crags
  • Loading branch information
salamca committed Apr 1, 2024
2 parents e05a749 + 3d2a424 commit 641a2d1
Show file tree
Hide file tree
Showing 30 changed files with 1,664 additions and 488 deletions.
245 changes: 107 additions & 138 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
"eslint-config-next": "^14.0.3",
"graphql": "^16.6.0",
"leaflet": "^1.9.4",
"next": "^14.0.3",
"next": "^14.1.4",
"next-cookies": "^2.0.3",
"next-usequerystate": "^1.13.0",
"next-usequerystate": "^1.13.1",
"react": "^18.2.0",
"react-aria": "^3.21.0",
"react-dom": "^18.2.0",
Expand Down
81 changes: 29 additions & 52 deletions src/app/[lang]/crag/[cragSlug]/components/crag-routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,7 @@ import {
Route,
Sector,
} from "../../../../../graphql/generated";
import {
createContext,
useEffect,
useLayoutEffect,
useRef,
useState,
} from "react";
import { createContext, useCallback, useLayoutEffect, useState } from "react";
import CragRouteList from "./crag-routes/crag-route-list";
import CragSector from "./crag-routes/crag-sector";
import CragRoutesActions from "./crag-routes/crag-routes-actions";
Expand All @@ -20,6 +14,7 @@ import {
parseAsInteger,
useQueryState,
} from "next-usequerystate";
import useResizeObserver from "@/hooks/useResizeObserver";

interface Props {
crag: Crag;
Expand Down Expand Up @@ -47,7 +42,7 @@ interface SearchOptions {
}

interface CragRoutesState {
compact: boolean;
compact: boolean | null;
combine: boolean;
selectedColumns: string[];
noSectors: boolean;
Expand Down Expand Up @@ -75,7 +70,7 @@ interface CragRoutesContextType {

const CragRoutesContext = createContext<CragRoutesContextType>({
cragRoutesState: {
compact: true,
compact: null,
combine: false,
selectedColumns: [],
noSectors: false,
Expand Down Expand Up @@ -197,7 +192,7 @@ const cragRouteListColumns: CragRouteListColumn[] = [

function CragRoutes({ crag, mySummary }: Props) {
const [cragRoutesState, setCragRoutesState] = useState<CragRoutesState>({
compact: true,
compact: null,
combine: false,
selectedColumns: cragRouteListColumns
.filter(({ isDefault }) => isDefault)
Expand All @@ -210,53 +205,32 @@ function CragRoutes({ crag, mySummary }: Props) {
// no sectors crag: a crag that is physically only one wall and will never be split into multiple sectors
});

const [compact, setCompact] = useState(true);
const [breakpoint, setBreakpoint] = useState(500);

const ascents = new Map(
mySummary.map((ascent) => [ascent.route.id, ascent.ascentType])
);

// Resize observer to detect when to switch to compact mode according to selected columns width
useEffect(() => {
setBreakpoint(
cragRouteListColumns
.filter(
(c) =>
cragRoutesState.selectedColumns.includes(c.name) ||
(cragRoutesState.combine && c.name === "sector")
)
.reduce((acc, c) => acc + c.width, 0) +
(cragRoutesState.combine ? 0 : 32)
);
// if we combined by sector there is another padding level that should be considdered, hence +32px
}, [
cragRoutesState.selectedColumns,
cragRoutesState.selectedColumns.length,
cragRoutesState.combine,
]);

const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const elementToObserve = containerRef?.current;
if (!elementToObserve) {
return;
}
const neededWidth =
cragRouteListColumns
.filter(
(c) =>
cragRoutesState.selectedColumns.includes(c.name) ||
(cragRoutesState.combine && c.name === "sector")
)
.reduce((acc, c) => acc + c.width, 0) +
(cragRoutesState.combine ? 0 : 32);

const resizeObserver = new ResizeObserver((entries) => {
const availableWidth = entries[0].contentRect.width;
setCompact(availableWidth <= breakpoint);
});
resizeObserver.observe(elementToObserve);
const onResize = useCallback(
(target: HTMLDivElement, entry: ResizeObserverEntry) => {
const availableWidth = entry.contentRect.width;

return () => {
resizeObserver.disconnect();
};
}, [breakpoint]);

useEffect(() => {
setCragRoutesState((state) => ({ ...state, compact }));
}, [compact]);
setCragRoutesState((state) => ({
...state,
compact: availableWidth < neededWidth,
}));
},
[neededWidth]
);
const containerRef = useResizeObserver(onResize);

// Sectors collapse/expand
const [expandedSectors, setExpandedSectors] = useQueryState(
Expand Down Expand Up @@ -296,7 +270,10 @@ function CragRoutes({ crag, mySummary }: Props) {
cragRoutesState.noSectors ? "px-4" : ""
} xs:px-8`}
>
<div ref={containerRef}>
<div
ref={containerRef}
className={`${cragRoutesState.compact === null ? "opacity-0" : ""}`}
>
{cragRoutesState.combine ||
cragRoutesState.search?.query ||
cragRoutesState.noSectors ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import IconStarFull from "../../../../../../components/ui/icons/star-full";
import IconComment from "../../../../../../components/ui/icons/comment";
import IconCheck from "../../../../../../components/ui/icons/check";
import { IconSize } from "@/components/ui/icons/icon-size";
import { filterEntitiesBySearchTerm } from "@/utils/search-helpers";

interface Props {
crag: Crag;
Expand Down Expand Up @@ -71,35 +72,6 @@ function filterRoutesByFilter(
return routes;
}

function escape(searchTerm: string): string {
return searchTerm.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
}

function ignoreAccents(searchTerm: string): string {
return searchTerm
.replace(/[cčć]/gi, "[cčć]")
.replace(/[sš]/gi, "[sš]")
.replace(/[zž]/gi, "[zž]")
.replace(/[aàáâäæãåā]/gi, "[aàáâäæãåā]")
.replace(/[eèéêëēėę]/gi, "[eèéêëēėę]")
.replace(/[iîïíīįì]/gi, "[iîïíīįì]")
.replace(/[oôöòóœøōõ]/gi, "[oôöòóœøōõ]")
.replace(/[uûüùúū]/gi, "[uûüùúū]")
.replace(/[dđ]/gi, "[dđ]");
}

function filterRoutesBySearchTerm(
routes: Route[],
searchTerm: string
): Route[] {
searchTerm = searchTerm.toLowerCase();
searchTerm = escape(searchTerm);
searchTerm = ignoreAccents(searchTerm);
const regExp = new RegExp(searchTerm);

return routes.filter((route) => regExp.test(route.name.toLowerCase()));
}

function sortRoutes(
routes: Route[],
ascents: Map<string, string>,
Expand Down Expand Up @@ -160,7 +132,7 @@ function CragRouteList({ routes, crag, ascents }: Props) {
routes = filterRoutesByFilter(routes, ascents, cragRoutesState.filter);

if (cragRoutesState.search?.query) {
routes = filterRoutesBySearchTerm(routes, cragRoutesState.search.query);
routes = filterEntitiesBySearchTerm(routes, cragRoutesState.search.query);
}

routes = sortRoutes(routes, ascents, cragRoutesState.sort);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ function CragRouteCompact({ crag, route, ascent }: Props) {
<div className="flex items-center justify-between">
<div className="flex">
{displayColumn("difficulty") && (
<span className="pr-4">
<div className="-m-1 pr-4">
<RouteGrade route={route} crag={crag} />
</span>
</div>
)}
{displayColumn("length") && route.length && (
{displayColumn("length") && !!route.length && (
<span>{route.length} m</span>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function CragRoutesActions() {
: "flex justify-center"
}`}
>
<div className="flex items-center justify-center py-5">
<div className="flex items-center justify-center py-4 xs:py-5">
<div>
<Filter />
</div>
Expand Down
12 changes: 6 additions & 6 deletions src/app/[lang]/crag/[cragSlug]/info/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import Map from "@/components/map/map";
import Button from "@/components/ui/button";
import IconMissing from "@/components/ui/icons/missing";
import Link from "@/components/ui/link";
import { TMarker } from "@/components/map/lazy-map";
import { IconSize } from "@/components/ui/icons/icon-size";
import IconMore from "@/components/ui/icons/more";
import { TMarker } from "@/components/map/map-marker";

type TCragInfoPageParams = {
cragSlug: string;
Expand Down Expand Up @@ -94,7 +94,7 @@ async function CragInfoPage({ params }: { params: TCragInfoPageParams }) {
crag.maxRouteLength = 15;
crag.wallAngles = [WallAngle.Slab, WallAngle.Overhang];
crag.seasons = [Season.Summer, Season.Spring];
crag.rainProof = true;
crag.rainproof = true;

crag.coverImage = {
id: "",
Expand Down Expand Up @@ -131,7 +131,7 @@ async function CragInfoPage({ params }: { params: TCragInfoPageParams }) {
iconDataMissing.push("dolžinah smeri");
!crag.wallAngles && iconDataMissing.push("naklonu stene");
!crag.seasons && iconDataMissing.push("sezoni");
crag.rainProof === null && iconDataMissing.push("odpornosti na dež");
crag.rainproof === null && iconDataMissing.push("odpornosti na dež");

let iconDataMissingMsg;
let iconDataMissingActionLinkMsg;
Expand Down Expand Up @@ -560,7 +560,7 @@ function ApproachTimeHeightAnglesSeasonsAndRainproof({
</>
)}

{crag.rainProof !== null && (
{crag.rainproof !== null && (
<>
<IconGroupDivider
className={`
Expand All @@ -577,7 +577,7 @@ function ApproachTimeHeightAnglesSeasonsAndRainproof({
}
`}
/>
<div className={`${!!crag.rainProof ? "" : "text-neutral-300"}`}>
<div className={`${!!crag.rainproof ? "" : "text-neutral-300"}`}>
<IconRainproof size={IconSize.large} />
</div>
</>
Expand Down Expand Up @@ -626,7 +626,7 @@ gql`
approachTime
wallAngles
seasons
rainProof
rainproof
coverImage {
id
path
Expand Down
93 changes: 0 additions & 93 deletions src/app/[lang]/crags/[countrySlug]/page.tsx

This file was deleted.

Loading

0 comments on commit 641a2d1

Please sign in to comment.