diff --git a/components/ComparisonTable.tsx b/components/ComparisonTable.tsx index 208ed2b6..b6ea25e9 100644 --- a/components/ComparisonTable.tsx +++ b/components/ComparisonTable.tsx @@ -219,25 +219,21 @@ function ComparisonTable({ return } - const companyRoute = getCompanyURL(lowerCaseName, wikiId) - window.location.href = companyRoute + window.location.assign(getCompanyURL(lowerCaseName, wikiId)) } else { - const municipalityrRoute = `/kommun/${lowerCaseName}` - router.push(municipalityrRoute) + router.push(`/kommun/${lowerCaseName}`) } } return ( <> - {/* HACK: prevent table headers from changing size when toggling table rows. Not sure what causes the problem, but this fixes it. */} - {dataType === 'companies' ? ( - - - - - - ) : null} + {/* HACK: prevent table headers from changing size when changing data view. Not sure what causes the problem, but this fixes it. */} + + + + + {table.getHeaderGroups().map((headerGroup) => ( @@ -245,10 +241,6 @@ function ComparisonTable({ {headerGroup.headers.map((header) => { const currentSort = header.column.getIsSorted() return ( - // TODO: Ensure clicking table headers doesn't scroll to top. - // It almost seems like this could be by the table losing all its content - // just before re-rendering it. And since the table (or page) doesn't need as much scroll anymore, - // maybe it just shows the top of the table then again? ` background-color: rgba(0, 0, 0, 0.5); width: 100vw; height: 100vh; - z-index: 10; + z-index: 990; top: 0; left: 0; right: 0; diff --git a/next.config.js b/next.config.js index f30d4de3..14b14333 100644 --- a/next.config.js +++ b/next.config.js @@ -53,6 +53,11 @@ module.exports = withBundleAnalyzer({ destination: `${baseURL}/2024-06-Bolagsklimatkollen.pdf`, permanent: false, }, + { + source: '/corporateclimatechecker', + destination: `${baseURL}/2024-08_CorporateClimateChecker.pdf`, + permanent: false, + }, ] }, }) diff --git a/package-lock.json b/package-lock.json index c66acf8f..e6a6bee0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "react-mailchimp-subscribe": "^2.1.3", "react-markdown": "^9.0.1", "rehype-external-links": "^3.0.0", + "slugify": "^1.6.6", "styled-components": "^6.1.8", "vite": "^5.2.11" }, @@ -11922,6 +11923,15 @@ "node": ">=8" } }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", diff --git a/package.json b/package.json index 6037c5d9..af2f91f5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "react-mailchimp-subscribe": "^2.1.3", "react-markdown": "^9.0.1", "rehype-external-links": "^3.0.0", + "slugify": "^1.6.6", "styled-components": "^6.1.8", "vite": "^5.2.11" }, diff --git a/pages/_document.tsx b/pages/_document.tsx index 3e9cc004..8085bbf7 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -8,7 +8,9 @@ export default class MyDocument extends Document { render() { return ( - + + +
diff --git a/pages/index.tsx b/pages/index.tsx index 0f18391f..cc0dfd78 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -26,7 +26,7 @@ const Container = styled.div` align-items: center; ` -const CompanyReportNotice = styled(Link)` +const CompanyReportNotice = styled.div` background: ${({ theme }) => theme.newColors.orange2}; color: ${({ theme }) => theme.newColors.black3}; padding: 0.5rem 0.75rem; @@ -34,8 +34,9 @@ const CompanyReportNotice = styled(Link)` border-radius: 1rem; text-decoration: none !important; line-height: 1; - display: flex; + display: grid; align-items: center; + justify-content: center; gap: 8px; font-size: 0.875rem; @@ -44,14 +45,23 @@ const CompanyReportNotice = styled(Link)` white-space: nowrap; } - &:hover { - background: ${({ theme }) => theme.huePalette.orange['300']}; + div { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; + + a { + display: flex; + align-items: center; + gap: 0.25rem; + } } ` const IconExternalLink = styled(LucideExternalLink)` - height: 1.25rem; - width: 1.25rem; + height: 1rem; + width: 1rem; flex-shrink: 0; ` @@ -102,7 +112,7 @@ function StartPage({ companies, municipalities, initialDataGroup }: PropsType) { /> - +

{t('startPage:reportNotice.readReport')} @@ -110,7 +120,19 @@ function StartPage({ companies, municipalities, initialDataGroup }: PropsType) { {t('startPage:reportNotice.text')}

- +
+ + Svenska + + + + · + + + English + + +
[] => { header: t('startPage:companyView.scope1n2'), cell: (row) => { const scope1n2Emissions = row.cell.row.original.Emissions.Scope1n2 + const hasValue = Number.isFinite(scope1n2Emissions) // console.log({ row, Emissions: row.cell.row.original.Emissions }) // NOTE: The type does not match the actual values here. // TS thinks scope1n2Emissions has the type `CompanyScope`, but according to the logging above, // it is in fact just a number or null. // TODO: Fix this when we get data from the API - const scope1n2String = Number.isFinite(scope1n2Emissions) ? formatter.format(scope1n2Emissions as unknown as number) : notReported + const scope1n2String = hasValue ? formatter.format(scope1n2Emissions as unknown as number) : notReported return ( - + {scope1n2String} ) @@ -86,15 +87,16 @@ export const companyColumns = (t: TFunction): ColumnDef[] => { header: () => t('startPage:companyView.scope3'), cell: (row) => { const scope3Emissions = row.cell.row.original.Emissions.Scope3 + const hasValue = Number.isFinite(scope3Emissions) // console.log({ row, Emissions: row.cell.row.original.Emissions }) // NOTE: The type does not match the actual values here. // TS thinks scope3Emissions has the type `CompanyScope`, but according to the logging above, // it is in fact just a number or null. // TODO: Fix this when we get data from the API - const scope3String = Number.isFinite(scope3Emissions) ? formatter.format(scope3Emissions as unknown as number) : notReported + const scope3String = hasValue ? formatter.format(scope3Emissions as unknown as number) : notReported return ( - + {scope3String} ) diff --git a/utils/shared.ts b/utils/shared.ts index b24f346c..104b4363 100644 --- a/utils/shared.ts +++ b/utils/shared.ts @@ -1,3 +1,5 @@ +import { slugifyURL } from './slugifyURL' + export const normalizeString = (input: string) => input.replace('ä', 'a').replace('ö', 'o').replace('å', 'a').toLowerCase() export const toTitleCase = (str: string) => str.replace( @@ -5,10 +7,10 @@ export const toTitleCase = (str: string) => str.replace( (txt) => txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase(), ) -export const ONE_WEEK_MS = 60 * 60 * 24 * 7 +export const ONE_WEEK_MS = 1000 * 60 * 60 * 24 * 7 + +const baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:4321' : 'https://beta.klimatkollen.se' -export const getCompanyURL = (companyName: string, wikiId: string) => { - const baseURL = process.env.NODE_ENV === 'production' ? 'https://beta.klimatkollen.se' : 'http://localhost:4321' - const dashName = companyName.toLowerCase().replaceAll(' ', '-') - return `${baseURL}/foretag/${dashName}-${wikiId}` -} +export const getCompanyURL = (companyName: string, wikiId: string) => ( + `${baseURL}/foretag/${slugifyURL(companyName)}-${wikiId}` +) diff --git a/utils/slugifyURL.ts b/utils/slugifyURL.ts new file mode 100644 index 00000000..d3c25697 --- /dev/null +++ b/utils/slugifyURL.ts @@ -0,0 +1,12 @@ +import slugify from 'slugify' + +export const slugifyURL = (url: string, locale = 'sv') => ( + slugify(url, { + replacement: '-', // replace spaces with replacement character + remove: undefined, // remove characters that match regex + lower: true, // convert to lower case + strict: true, // strip special characters except replacement + locale, // locale identifier used to create locale-aware slugs + trim: true, // trim leading and trailing replacement chars + }) +)