{"version":3,"file":"Blog-CzTD0YZ-.js","sources":["../../../src/hooks/useTags.ts","../../../src/components/pages/blog/BlogFilter.tsx","../../../src/components/pages/blog/BlogSearch.tsx","../../../src/components/pages/blog/Blog.tsx"],"sourcesContent":["import { useRoute } from 'react-router5';\nimport { RouterState } from '../routerMiddleware';\nimport { Tag } from '../types';\n\nexport default function useTags(): Array {\n const { route } = useRoute();\n const state = route as RouterState;\n\n let tags = state?.data?.tags || [];\n\n if (state?.name.startsWith('blog')) {\n tags = tags.filter(t => state?.data?.articles.some(a =>\n a.tags.some(article_tag => article_tag.id === t.id)\n ))\n }\n\n return tags;\n}","import React, { useEffect, useState } from 'react';\nimport { styled } from 'styled-components';\nimport { faChevronDown } from '@fortawesome/free-solid-svg-icons';\nimport Link from '../../Link';\nimport Text from '../../Text';\nimport useTags from '../../../hooks/useTags';\nimport Dropdown from '../../Dropdown';\nimport {useRoute} from 'react-router5';\nimport Icon from '../../Icon';\n\ninterface DropdownTriggerProps {\n $isOpen: boolean,\n}\n\nconst DropdownTrigger = styled.div`\n align-items: center;\n background-color: var(--color-white);\n border-radius: var(--border-radius);\n border: 1px solid var(--color-iron-400);\n cursor: pointer;\n display: flex;\n font-weight: 500;\n justify-content: space-between;\n padding: .75rem;\n transition-duration: var(--transition-duration);\n transition-property: box-shadow;\n transition-timing-function: var(--transition-timing-function);\n user-select: none;\n\n &:hover {\n box-shadow: var(--box-shadow);\n }\n\n &:active {\n box-shadow: none;\n }\n\n > svg {\n transform: ${props => props.$isOpen ? 'rotate(180deg)' : 'roate(0)'};\n transition-duration: var(--transition-duration);\n transition-property: transform;\n transition-timing-function: var(--transition-timing-function);\n height: 1em;\n width: 1em;\n max-height: 1em;\n max-width: 1em;\n }\n`;\n\nconst DropdownItem = styled(Link)`\n border-bottom: 1px solid var(--color-iron-300);\n display: block;\n font-family: var(--font-family-mono);\n font-size: var(--font-size-sm);\n padding-bottom: var(--baseline-sm);\n padding-left: .75rem;\n padding-right: .75rem;\n padding-top: var(--baseline-sm);\n user-select: none;\n\n &:first-child {\n background-color: var(--color-white);\n position: sticky;\n top: 0;\n font-family: var(--font-family);\n font-weight: 600;\n }\n\n &:hover {\n background-color: var(--color-iron-300);\n }\n`;\n\nexport default function BlogFilter() {\n const tags = useTags();\n const {route} = useRoute();\n\n const [tagDropdown, setTagDropdown] = useState(false);\n const [currentTag, setCurrentTag] = useState(\n tags.find(t => t.name.toLocaleLowerCase() === route.params.slug)?.name\n || route.params.slug);\n\n useEffect(() => {\n changeTagHandle(tags.find(t => t.name.toLocaleLowerCase() === route.params.slug)?.name\n || route.params.slug);\n }, [route]);\n\n const changeTagHandle = (name: string) => {\n setCurrentTag(name);\n setTagDropdown(false);\n }\n\n return (\n
\n setTagDropdown(!tagDropdown)} $isOpen={tagDropdown} >\n \n \n \n \n changeTagHandle('')}>\n {tags.sort((a, b) => a.name !== b.name ? a.name < b.name ? -1 : 1 : 0).map((tag, index) => (\n changeTagHandle(tag.name)}>{tag.name}\n ))}\n \n
\n );\n}\n","import { styled } from 'styled-components';\nimport { useRoute } from 'react-router5';\nimport { useEffect, useState } from 'react';\nimport useBlogSearchSuggestions, { Suggestion } from '../../../hooks/useBlogSearchSuggestions';\n\nconst StyledForm = styled.form`\n position: relative;\n margin-bottom: 1rem;\n`;\n\nconst StyledInput = styled.input`\n width: 100%;\n padding: .75rem;\n color: var(--color-iron-900);\n border-radius: var(--border-radius);\n border: 1px solid var(--color-iron-400);\n font-family: var(--font-family);\n font-weight: 500;\n font-size: var(--font-size-md);\n margin-bottom: var(--baseline-sm);\n display: block;\n line-height: 1.5;\n\n &:hover {\n box-shadow: var(--box-shadow);\n }\n`;\n\nconst StyledDropdownItem = styled.a<{ $selected: boolean; }>`\n border-bottom: 1px solid var(--color-iron-300);\n display: block;\n font-family: var(--font-family-mono);\n font-size: var(--font-size-sm);\n padding-bottom: var(--baseline-sm);\n padding-left: .75rem;\n padding-right: .75rem;\n padding-top: var(--baseline-sm);\n user-select: none;\n \n ${props => props.$selected && `\n background-color: var(--color-white);\n position: sticky;\n top: 0;\n font-family: var(--font-family);\n font-weight: 600;\n `}\n \n &:hover {\n background-color: var(--color-iron-300);\n }\n`;\n\nconst StyledDropdown = styled.div`\n position: absolute;\n z-index: 102;\n display: block;\n background-color: var(--color-white);\n border-radius: var(--border-radius);\n border: 1px solid var(--color-iron-400);\n box-shadow: rgba(100, 100, 111, 0.15) 0px 7px 29px 0px;\n width: 100%;\n min-width: 3rem;\n`;\n\nexport default function BlogSearch() {\n const { route, router } = useRoute();\n const [search, setSearch] = useState(route?.params?.search || '');\n const [debounced, setDebounced] = useState(search);\n const suggestions: Suggestion[] = useBlogSearchSuggestions(search);\n const [selected, setSelected] = useState(null);\n const [focus, setFocus] = useState(false);\n\n // debounce on user input\n useEffect(() => {\n const timeout = setTimeout(() => {\n setDebounced(search);\n }, 200);\n\n return () => clearTimeout(timeout);\n }, [search]);\n\n // perform search + navigation\n useEffect(() => {\n if (debounced && debounced !== route?.params?.search) {\n router.navigate('blog', {\n lang: 'en',\n search: debounced || undefined,\n });\n }\n }, [debounced, search, router]);\n\n const getSelectedIndex = (direction: -1 | 1): null | number => {\n if (suggestions.length > 0) {\n let index = 0;\n if (selected !== null) {\n index = suggestions.findIndex(({slug}) => slug === selected.slug);\n } else {\n return 0;\n }\n if (index === -1) {\n return 0;\n }\n index += direction;\n if (index < 0) {\n return suggestions.length - 1;\n }\n if (index === suggestions.length) {\n return 0;\n }\n return index;\n }\n return null;\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n const i = getSelectedIndex(+1);\n if (i !== null) {\n setSelected(suggestions[i]);\n }\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n const i = getSelectedIndex(-1);\n if (i !== null) {\n setSelected(suggestions[i]);\n }\n } else if (e.key === 'Enter' && selected !== null) {\n setSearch(selected.slug);\n } else if (e.key === 'Escape') {\n setSelected(null);\n }\n }\n \n return (\n {\n e.preventDefault();\n setFocus(false);\n setDebounced(search); \n }}\n >\n { setFocus(true); setSelected(null); setSearch(e.target.value); }}\n onFocus={() => setFocus(true)}\n />\n {focus && suggestions.length > 0 && (\n \n {suggestions.map((suggestion) =>\n {\n setFocus(false);\n if (suggestion.type === 'tag') {\n router.navigate('blog.tag', {\n lang: 'en',\n slug: suggestion.slug,\n });\n } else {\n router.navigate('blog', {\n lang: 'en',\n type: suggestion.type,\n search: suggestion.slug,\n });\n }\n }}\n >\n {suggestion.slug}\n \n )}\n \n )}\n \n );\n}\n","import React, { ReactElement } from 'react';\nimport BlogFilter from './BlogFilter';\nimport BlogList from './BlogList';\nimport Container from '../../layout/Container';\nimport Grid from '../../layout/Grid';\nimport Heading from '../../Heading';\nimport HeroAnimated from '../../HeroAnimated';\nimport Layout from '../../layout/Layout';\nimport Paragraph from '../../Paragraph';\nimport Col from '../../layout/Col';\nimport Sections from '../../layout/Sections';\nimport { Seo } from '../../seo/Seo';\nimport { canonicalDomain } from '../../seo/DefaultSeo';\nimport Button from '../../Button';\nimport Icon from '../../Icon';\nimport { faRss } from '@fortawesome/free-solid-svg-icons';\nimport BlogSearch from './BlogSearch';\n\nexport default function Blog(): ReactElement {\n return (\n \n \n {/* We want all listings of the blog to have the English full blog list as the canonical url */}\n \n \n \n \n Blog\n \n Tech blog on web, security & embedded\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n );\n}\n"],"names":["useTags","route","useRoute","state","tags","_a","t","a","article_tag","DropdownTrigger","styled","div","withConfig","displayName","componentId","props","$isOpen","DropdownItem","Link","BlogFilter","tagDropdown","setTagDropdown","useState","currentTag","setCurrentTag","find","name","toLocaleLowerCase","params","slug","useEffect","changeTagHandle","jsxs","jsx","Text","Icon","faChevronDown","Dropdown","sort","b","map","tag","index","StyledForm","form","StyledInput","input","StyledDropdownItem","$selected","StyledDropdown","BlogSearch","router","search","setSearch","debounced","setDebounced","suggestions","useBlogSearchSuggestions","selected","setSelected","focus","setFocus","timeout","setTimeout","clearTimeout","navigate","lang","undefined","getSelectedIndex","direction","length","findIndex","handleKeyDown","e","key","preventDefault","i","target","value","suggestion","type","Blog","Layout","Seo","canonicalDomain","Sections","HeroAnimated","Heading","Paragraph","Container","Grid","md","lg","Col","Button","faRss","xl","BlogList"],"mappings":"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"}