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