mirror of https://github.com/mkrhere/pw2
Compare commits
6 Commits
a50e46f137
...
01a4bea711
Author | SHA1 | Date |
---|---|---|
Muthu Kumar | 01a4bea711 | 5 months ago |
Muthu Kumar | c11f785409 | 5 months ago |
Muthu Kumar | 761ab66d98 | 5 months ago |
Muthu Kumar | 55e03e845b | 5 months ago |
Muthu Kumar | be2c320183 | 5 months ago |
Muthu Kumar | 5aa0ac4e6e | 5 months ago |
15 changed files with 2898 additions and 1913 deletions
File diff suppressed because it is too large
After Width: | Height: | Size: 252 B |
@ -0,0 +1,124 @@ |
|||||
|
import React from "react"; |
||||
|
import { css, cx } from "@emotion/css"; |
||||
|
import { HookSet } from "../../util/useSearchParams"; |
||||
|
import { ReactComponent as Cross } from "../../assets/cross.svg"; |
||||
|
|
||||
|
type Tags = HookSet<string>; |
||||
|
|
||||
|
const tag = css` |
||||
|
cursor: pointer; |
||||
|
border-radius: 0.5rem; |
||||
|
padding: 0.5rem 0.9rem 0.5rem 0.6rem; |
||||
|
font-size: 0.85rem; |
||||
|
background-color: transparent; |
||||
|
border: 1px solid var(--card-bg); |
||||
|
color: var(--text-colour); |
||||
|
transition: background-color 150ms; |
||||
|
|
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 0.5rem; |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: var(--card-tags-hover); |
||||
|
} |
||||
|
|
||||
|
&.active { |
||||
|
background-color: var(--card-tags); |
||||
|
} |
||||
|
`;
|
||||
|
|
||||
|
export const Tag = (props: { tag: string; selected: Tags }) => { |
||||
|
const { selected } = props; |
||||
|
|
||||
|
const active = selected.has(props.tag); |
||||
|
const select = () => { |
||||
|
if (selected.has(props.tag)) selected.remove(props.tag); |
||||
|
else selected.add(props.tag); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<button className={cx(tag, { active })} onClick={select}> |
||||
|
<span |
||||
|
className={cx( |
||||
|
css` |
||||
|
transition: transform 100ms ease-in-out; |
||||
|
overflow: hidden; |
||||
|
transform: rotate(45deg); |
||||
|
width: 0.85rem; |
||||
|
|
||||
|
&.active { |
||||
|
transform: rotate(0deg); |
||||
|
} |
||||
|
`,
|
||||
|
{ active }, |
||||
|
)}> |
||||
|
<Cross |
||||
|
className={css` |
||||
|
display: block; |
||||
|
height: 0.85rem; |
||||
|
width: 0.85rem; |
||||
|
fill: var(--text-colour); |
||||
|
`}
|
||||
|
/> |
||||
|
</span> |
||||
|
{props.tag} |
||||
|
</button> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
const clear = css` |
||||
|
border: none; |
||||
|
color: var(--primary-colour); |
||||
|
opacity: 1; |
||||
|
transition: opacity 200ms; |
||||
|
|
||||
|
&.hide { |
||||
|
opacity: 0; |
||||
|
user-select: none; |
||||
|
cursor: unset; |
||||
|
height: 0; |
||||
|
} |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: transparent; |
||||
|
} |
||||
|
`;
|
||||
|
|
||||
|
export const Clear = (props: { selected: Tags }) => { |
||||
|
const { selected } = props; |
||||
|
|
||||
|
return ( |
||||
|
<button |
||||
|
className={cx(tag, clear, { hide: !selected.size })} |
||||
|
onClick={selected.clear}> |
||||
|
<Cross |
||||
|
className={css` |
||||
|
display: block; |
||||
|
height: 0.85rem; |
||||
|
width: 0.85rem; |
||||
|
fill: var(--text-colour); |
||||
|
`}
|
||||
|
/> |
||||
|
Clear filters |
||||
|
</button> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export const Tags = (props: { tags: string[]; selected: Tags }) => { |
||||
|
const { tags, selected } = props; |
||||
|
|
||||
|
return ( |
||||
|
<div |
||||
|
className={css` |
||||
|
display: flex; |
||||
|
gap: 0.5rem; |
||||
|
flex-wrap: wrap; |
||||
|
`}>
|
||||
|
{tags.map(tag => ( |
||||
|
<Tag key={tag} tag={tag} selected={selected} /> |
||||
|
))} |
||||
|
<Clear selected={selected} /> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
@ -0,0 +1 @@ |
|||||
|
export const offscreenWidth = "82rem"; |
@ -0,0 +1,57 @@ |
|||||
|
import { useState } from "react"; |
||||
|
import useLocation from "wouter/use-location"; |
||||
|
|
||||
|
export type HookSet<T> = { |
||||
|
set: Set<T>; |
||||
|
size: number; |
||||
|
add: (value: T) => void; |
||||
|
remove: (value: T) => void; |
||||
|
clear: () => void; |
||||
|
has: (value: T) => boolean; |
||||
|
}; |
||||
|
|
||||
|
const flatten = (set: Set<string>, key: string) => |
||||
|
Array.from(set) |
||||
|
.map(param => `${key}=${encodeURIComponent(param)}`) |
||||
|
.join("&"); |
||||
|
|
||||
|
export function useSearchParams(key: string): HookSet<string> { |
||||
|
const [, navigate] = useLocation(); |
||||
|
const [params, setParams] = useState( |
||||
|
() => new Set(new URLSearchParams(window.location.search).getAll(key)), |
||||
|
); |
||||
|
|
||||
|
const add = (value: string) => { |
||||
|
setParams(prevSet => { |
||||
|
const newSet = new Set(prevSet); |
||||
|
newSet.add(value); |
||||
|
navigate("?" + flatten(newSet, key), { replace: true }); |
||||
|
return newSet; |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const remove = (value: string) => { |
||||
|
setParams(prevSet => { |
||||
|
const newSet = new Set(prevSet); |
||||
|
newSet.delete(value); |
||||
|
navigate("?" + flatten(newSet, key), { replace: true }); |
||||
|
return newSet; |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const clear = () => { |
||||
|
setParams(new Set()); |
||||
|
navigate("?", { replace: true }); |
||||
|
}; |
||||
|
|
||||
|
return { |
||||
|
set: params, |
||||
|
size: params.size, |
||||
|
add, |
||||
|
remove, |
||||
|
clear, |
||||
|
has: (value: string) => params.has(value), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default useSearchParams; |
Loading…
Reference in new issue