Merged in fix/SW-1041-design-feedback-select-hotel (pull request #986)
fix(SW-1041): fix UI design feedback * fix(SW-1041): fix UI design feedback * fix(SW-1041): small fix * fix(SW-1041): add filter and sort badge * fix(SW-1041): update activefilter when entering map view * fix(SW-1041): create hook with activefilters * fix(SW-1041): hook only sets filter * fix(SW-1041): fix padding breadcrumbs * fix(SW-1041): rename hook * fix(SW-1041): fix double scroll Approved-by: Pontus Dreij Approved-by: Niclas Edenvin
This commit is contained in:
@@ -3,6 +3,4 @@
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
margin-bottom: var(--Spacing-x2);
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@@ -59,22 +59,42 @@
|
||||
|
||||
.content {
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x3);
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sorter {
|
||||
padding: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2) var(--Spacing-x-half)
|
||||
var(--Spacing-x2);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.badge {
|
||||
background-color: var(--Base-Text-Accent);
|
||||
border-radius: var(--Corner-radius-xLarge);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.filters {
|
||||
padding: var(--Spacing-x2);
|
||||
padding-top: calc(var(--Spacing-x3) + var(--Spacing-x-half));
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.filters ul {
|
||||
margin-top: var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.filters ul li {
|
||||
padding-bottom: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: right;
|
||||
padding: var(--Spacing-x-one-and-half);
|
||||
@@ -93,11 +113,15 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
padding: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x3) var(--Spacing-x2);
|
||||
flex: 0 0 auto;
|
||||
border-top: 1px solid var(--Base-Border-Subtle);
|
||||
}
|
||||
@@ -112,6 +136,11 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: block;
|
||||
padding: 0 var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
@@ -139,6 +168,10 @@
|
||||
overflow-y: unset;
|
||||
}
|
||||
|
||||
.sorter {
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.sorter,
|
||||
.filters,
|
||||
.footer,
|
||||
@@ -158,19 +191,27 @@
|
||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.filters aside h1 {
|
||||
margin-bottom: var(--Spacing-x2);
|
||||
.filters aside > form {
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.filters aside > div:last-child {
|
||||
margin-top: var(--Spacing-x4);
|
||||
padding-bottom: 0;
|
||||
.filters aside form > div:last-child {
|
||||
margin-top: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.filters aside ul {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-top: var(--Spacing-x3);
|
||||
margin-top: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.filters ul li:hover {
|
||||
background: var(--UI-Input-Controls-Surface-Hover);
|
||||
border-radius: var(--Corner-radius-Medium,);
|
||||
outline: none;
|
||||
}
|
||||
.filters ul li {
|
||||
padding: var(--Spacing-x1) var(--Spacing-x-one-and-half);
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1024) {
|
||||
|
||||
@@ -13,7 +13,9 @@ import { useHotelFilterStore } from "@/stores/hotel-filters"
|
||||
import { CloseLargeIcon, FilterIcon } from "@/components/Icons"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import useInitializeFiltersFromUrl from "@/hooks/useInitializeFiltersFromUrl"
|
||||
|
||||
import HotelFilter from "../HotelFilter"
|
||||
import HotelSorter from "../HotelSorter"
|
||||
@@ -26,15 +28,20 @@ export default function FilterAndSortModal({
|
||||
filters,
|
||||
}: FilterAndSortModalProps) {
|
||||
const intl = useIntl()
|
||||
useInitializeFiltersFromUrl()
|
||||
const resultCount = useHotelFilterStore((state) => state.resultCount)
|
||||
const setFilters = useHotelFilterStore((state) => state.setFilters)
|
||||
const activeFilters = useHotelFilterStore((state) => state.activeFilters)
|
||||
|
||||
return (
|
||||
<>
|
||||
<DialogTrigger>
|
||||
<Button intent="secondary" size="small" theme="base">
|
||||
<FilterIcon color="burgundy" />
|
||||
<Button intent="secondary" size="small" theme="base" variant="icon">
|
||||
<FilterIcon color="baseTextHighcontrast" />
|
||||
{intl.formatMessage({ id: "Filter and sort" })}
|
||||
{activeFilters.length > 0 && (
|
||||
<Footnote className={styles.badge}>{activeFilters.length}</Footnote>
|
||||
)}
|
||||
</Button>
|
||||
<ModalOverlay className={styles.overlay} isDismissable>
|
||||
<Modal className={styles.modal}>
|
||||
@@ -60,7 +67,9 @@ export default function FilterAndSortModal({
|
||||
<div className={styles.sorter}>
|
||||
<HotelSorter />
|
||||
</div>
|
||||
<Divider color="subtle" className="divider" />
|
||||
<div className={styles.divider}>
|
||||
<Divider color="subtle" />
|
||||
</div>
|
||||
<div className={styles.filters}>
|
||||
<HotelFilter filters={filters} />
|
||||
</div>
|
||||
@@ -76,7 +85,6 @@ export default function FilterAndSortModal({
|
||||
{ count: resultCount }
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => setFilters([])}
|
||||
intent="text"
|
||||
|
||||
@@ -26,4 +26,5 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
forced-color-adjust: none;
|
||||
background: var(--UI-Input-Controls-Surface-Normal);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
.facilities ul {
|
||||
margin-top: var(--Spacing-x2);
|
||||
}
|
||||
.facilities:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: grid;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useHotelFilterStore } from "@/stores/hotel-filters"
|
||||
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import useInitializeFiltersFromUrl from "@/hooks/useInitializeFiltersFromUrl"
|
||||
|
||||
import FilterCheckbox from "./FilterCheckbox"
|
||||
|
||||
@@ -20,19 +21,9 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
|
||||
const searchParams = useSearchParams()
|
||||
const pathname = usePathname()
|
||||
const toggleFilter = useHotelFilterStore((state) => state.toggleFilter)
|
||||
const setFilters = useHotelFilterStore((state) => state.setFilters)
|
||||
useInitializeFiltersFromUrl()
|
||||
const activeFilters = useHotelFilterStore((state) => state.activeFilters)
|
||||
|
||||
// Initialize the filters from the URL
|
||||
useEffect(() => {
|
||||
const filtersFromUrl = searchParams.get("filters")
|
||||
if (filtersFromUrl) {
|
||||
setFilters(filtersFromUrl.split(","))
|
||||
} else {
|
||||
setFilters([])
|
||||
}
|
||||
}, [searchParams, setFilters])
|
||||
|
||||
// Update the URL when the filters changes
|
||||
useEffect(() => {
|
||||
const newSearchParams = new URLSearchParams(searchParams)
|
||||
@@ -60,42 +51,46 @@ export default function HotelFilter({ className, filters }: HotelFiltersProps) {
|
||||
|
||||
return (
|
||||
<aside className={`${styles.container} ${className}`}>
|
||||
<Title as="h4">{intl.formatMessage({ id: "Filter by" })}</Title>
|
||||
<div className={styles.facilities}>
|
||||
<Subtitle>{intl.formatMessage({ id: "Hotel facilities" })}</Subtitle>
|
||||
<ul>
|
||||
{filters.facilityFilters.map((filter) => (
|
||||
<li key={`li-${filter.id}`} className={styles.filter}>
|
||||
<FilterCheckbox
|
||||
name={filter.name}
|
||||
id={filter.id.toString()}
|
||||
onChange={() => toggleFilter(filter.id.toString())}
|
||||
isSelected={
|
||||
!!activeFilters.find((f) => f === filter.id.toString())
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<form>
|
||||
<Title as="h4">{intl.formatMessage({ id: "Filter by" })}</Title>
|
||||
<div className={styles.facilities}>
|
||||
<Subtitle>{intl.formatMessage({ id: "Hotel facilities" })}</Subtitle>
|
||||
<ul>
|
||||
{filters.facilityFilters.map((filter) => (
|
||||
<li key={`li-${filter.id}`} className={styles.filter}>
|
||||
<FilterCheckbox
|
||||
name={filter.name}
|
||||
id={filter.id.toString()}
|
||||
onChange={() => toggleFilter(filter.id.toString())}
|
||||
isSelected={
|
||||
!!activeFilters.find((f) => f === filter.id.toString())
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className={styles.facilities}>
|
||||
<Subtitle>{intl.formatMessage({ id: "Hotel surroundings" })}</Subtitle>
|
||||
<ul>
|
||||
{filters.surroundingsFilters.map((filter) => (
|
||||
<li key={`li-${filter.id}`} className={styles.filter}>
|
||||
<FilterCheckbox
|
||||
name={filter.name}
|
||||
id={filter.id.toString()}
|
||||
onChange={() => toggleFilter(filter.id.toString())}
|
||||
isSelected={
|
||||
!!activeFilters.find((f) => f === filter.id.toString())
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={styles.facilities}>
|
||||
<Subtitle>
|
||||
{intl.formatMessage({ id: "Hotel surroundings" })}
|
||||
</Subtitle>
|
||||
<ul>
|
||||
{filters.surroundingsFilters.map((filter) => (
|
||||
<li key={`li-${filter.id}`} className={styles.filter}>
|
||||
<FilterCheckbox
|
||||
name={filter.name}
|
||||
id={filter.id.toString()}
|
||||
onChange={() => toggleFilter(filter.id.toString())}
|
||||
isSelected={
|
||||
!!activeFilters.find((f) => f === filter.id.toString())
|
||||
}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,13 +25,20 @@ export default function MobileMapButtonContainer({
|
||||
|
||||
return (
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button asChild variant="icon" intent="secondary" size="small">
|
||||
<Button
|
||||
asChild
|
||||
theme="base"
|
||||
variant="icon"
|
||||
intent="secondary"
|
||||
size="small"
|
||||
>
|
||||
<Link
|
||||
href={selectHotelMap(lang)}
|
||||
color="baseButtonTextOnFillNormal"
|
||||
keepSearchParams
|
||||
color="burgundy"
|
||||
weight="bold"
|
||||
>
|
||||
<MapIcon color="burgundy" />
|
||||
<MapIcon color="baseTextHighcontrast" />
|
||||
{intl.formatMessage({ id: "See on map" })}
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.container .listingContainer .filterContainer > button {
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container .closeButton {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user