├── .content-collections ├── cache │ ├── blogpost │ │ └── agent_matching │ │ │ └── fe2ae60d7d38bb914378c8e77b3b4c538b2e9a86a9657d4343988d8890201a9a.cache │ ├── content-collection-config.mjs │ ├── helppost │ │ ├── become_provider │ │ │ └── 4fae9bb8d4cfc77639f0218eab41e6494a0681bd21ecea785dedc041bda123e8.cache │ │ ├── how_to_post_project │ │ │ └── 69994e16b8fd56f4bc2b97b3cf8f69e733672b8fbfea20648b5df7dd3700ab60.cache │ │ ├── integrations_overview │ │ │ └── 0a89c930f9ced244c961acb6bfb15f2e4b881da21ab2ee69c51a307722f5e3f4.cache │ │ ├── success_stories │ │ │ └── db6a6948ee9a3bf05b759b0fd1eef313aeeb4ad82fa5d426266c1d34e6b67869.cache │ │ └── what_is_dub │ │ │ └── 8ebe9a536d4b8cd51d4f056b3afebfe7675f52f71ecf8fab0d0ad15b44b41347.cache │ └── mapping.json └── generated │ ├── allBlogPosts.js │ ├── allChangelogPosts.js │ ├── allCustomersPosts.js │ ├── allHelpPosts.js │ ├── allIntegrationsPosts.js │ ├── allLegalPosts.js │ ├── allMarketReports.js │ ├── allPropertyPosts.js │ ├── index.d.ts │ └── index.js ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── .vscode └── settings.json ├── README.md ├── content-collections.ts ├── next.config.mjs ├── package.json ├── pnpm-lock.yaml ├── postcss.config.mjs ├── public ├── DatabaseLogo.tsx ├── Propdock.svg ├── _static │ ├── clients │ │ └── corponor.svg │ └── integrasjoner │ │ ├── brreg.svg │ │ ├── fiken.svg │ │ ├── kartverket.svg │ │ ├── poweroffice.svg │ │ ├── propcloud.svg │ │ ├── propely.svg │ │ ├── signicat.svg │ │ ├── tripletex.svg │ │ └── visma.svg ├── blocks.svg ├── changelog │ ├── v316.webp │ └── v317.webp ├── fonts │ └── NanumPenScript.woff2 ├── images │ ├── break.webp │ ├── cool.webp │ ├── founders.webp │ ├── hero-dark.webp │ ├── hero-light.webp │ ├── home.webp │ ├── release.webp │ ├── testimonial.webp │ ├── working.webp │ └── workplace.webp ├── manifest.json └── opengraph-image.png ├── src ├── app │ ├── (blog) │ │ └── blog │ │ │ ├── (index) │ │ │ ├── category │ │ │ │ └── [slug] │ │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ │ └── (post) │ │ │ └── [slug] │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── (help) │ │ └── help │ │ │ ├── article │ │ │ └── [slug] │ │ │ │ └── page.tsx │ │ │ ├── category │ │ │ └── [slug] │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── not-found.tsx │ │ │ └── page.tsx │ ├── (integrasjoner) │ │ └── integrasjoner │ │ │ ├── [slug] │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── actions │ │ ├── investor │ │ │ └── set-view-count.ts │ │ └── onboarding │ │ │ ├── onboarding.ts │ │ │ └── search-organization.ts │ ├── api │ │ └── og │ │ │ └── help │ │ │ └── route.tsx │ ├── early-access │ │ └── page.tsx │ ├── favicon.ico │ ├── globals.css │ ├── investor │ │ └── page.tsx │ ├── kontakt │ │ └── page.tsx │ ├── kunder │ │ ├── [slug] │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ └── page.tsx │ ├── layout.tsx │ ├── markedsinnsikt │ │ ├── kart │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ └── page.tsx │ ├── not-found.tsx │ ├── om-oss │ │ ├── layout.tsx │ │ └── page.tsx │ ├── onboarding │ │ ├── layout.tsx │ │ └── page.tsx │ ├── page.tsx │ ├── pricing │ │ ├── layout.tsx │ │ └── page.tsx │ ├── propdock │ │ ├── dashboard │ │ │ └── map │ │ │ │ └── page.tsx │ │ ├── eiendom │ │ │ └── page.tsx │ │ ├── exit-strategi │ │ │ └── page.tsx │ │ ├── finansiering │ │ │ └── page.tsx │ │ ├── leietakere │ │ │ └── page.tsx │ │ ├── marked │ │ │ └── page.tsx │ │ ├── page.tsx │ │ ├── regnskap │ │ │ └── page.tsx │ │ ├── selskap │ │ │ └── page.tsx │ │ ├── simulering │ │ │ └── page.tsx │ │ └── verdivurdering │ │ │ └── page.tsx │ ├── robots.ts │ ├── siteConfig.ts │ ├── sitemap.ts │ └── tjenester │ │ ├── page.tsx │ │ └── verdsettelse │ │ └── page.tsx ├── components │ ├── Accordion.tsx │ ├── AreaChart.tsx │ ├── Arrow.tsx │ ├── Badge.tsx │ ├── BarChart.tsx │ ├── Button.tsx │ ├── Card.tsx │ ├── Checkbox.tsx │ ├── Code.tsx │ ├── ComboChart.tsx │ ├── CopyToClipboard.tsx │ ├── Drawer.tsx │ ├── Dropdown.tsx │ ├── Input.tsx │ ├── Label.tsx │ ├── LineChart.tsx │ ├── Popover.tsx │ ├── RadioCardGroup.tsx │ ├── RadioGroup.tsx │ ├── Select.tsx │ ├── Slider.tsx │ ├── Switch.tsx │ ├── TabNavigation.tsx │ ├── Table.tsx │ ├── Tabs.tsx │ ├── ThemeSwitch.tsx │ ├── Tooltip.tsx │ ├── blog │ │ ├── author.tsx │ │ ├── blog-card.tsx │ │ ├── blog-layout-hero.tsx │ │ ├── category-card.tsx │ │ ├── cmdk.tsx │ │ ├── copy-box.tsx │ │ ├── customers.tsx │ │ ├── feedback.tsx │ │ ├── help-article-link.tsx │ │ ├── icons │ │ │ ├── expanding-arrow.tsx │ │ │ └── magic.tsx │ │ ├── integrations.tsx │ │ ├── legal.tsx │ │ ├── logos.tsx │ │ ├── max-width-wrapper.tsx │ │ ├── mdx.tsx │ │ ├── modal.tsx │ │ ├── popover.tsx │ │ ├── search-button.tsx │ │ ├── table-of-contents.tsx │ │ ├── testimonials-mobile.tsx │ │ ├── testimonials.tsx │ │ └── zoom-image.tsx │ ├── cal-embed.tsx │ ├── data │ │ ├── data.ts │ │ ├── generateData.js │ │ ├── overview-data.ts │ │ └── schema.ts │ ├── footer.tsx │ ├── forms │ │ └── ContactForm.tsx │ ├── header.tsx │ ├── investor │ │ ├── carousel-toolbar.tsx │ │ ├── carousel.tsx │ │ ├── copy-input.tsx │ │ ├── icons.tsx │ │ ├── overview.png │ │ ├── pitch-carousel.tsx │ │ ├── reciept.png │ │ ├── section-book.tsx │ │ ├── section-business-model.tsx │ │ ├── section-demo.tsx │ │ ├── section-expansion.tsx │ │ ├── section-future-growth.tsx │ │ ├── section-growth-strategy.tsx │ │ ├── section-market.tsx │ │ ├── section-problem.tsx │ │ ├── section-solution.tsx │ │ ├── section-start.tsx │ │ ├── section-team.tsx │ │ ├── section-traction.tsx │ │ └── ui.tsx │ ├── markedsinnsikt │ │ ├── Chart-main-page.tsx │ │ ├── MarkedsKart.tsx │ │ ├── PageShell.tsx │ │ ├── SideNav.tsx │ │ └── Top-kpi-card.tsx │ ├── mdx.tsx │ ├── propdock │ │ ├── DcfChart.tsx │ │ ├── FeatureComparison.tsx │ │ ├── FeatureShowcase.tsx │ │ ├── Navigation.tsx │ │ ├── ProcessFlow.tsx │ │ ├── ProgressCircle.tsx │ │ ├── PropertyMapOverview.tsx │ │ ├── TablePageNavigation.tsx │ │ ├── YieldLineChart.tsx │ │ ├── eiendom │ │ │ └── PropertyMap.tsx │ │ ├── exit-strategi │ │ │ ├── AssumableFinancingCalculator.tsx │ │ │ ├── ExitStrategyPlanning.tsx │ │ │ ├── FixedVsVariableRateChart.tsx │ │ │ ├── LoanAmortizationChart.tsx │ │ │ ├── OptimalHoldPeriodCalculator.tsx │ │ │ └── PrepaymentAnalysisCalculator.tsx │ │ ├── finansiering │ │ │ └── DebtStructuring.tsx │ │ ├── leietakere │ │ │ └── TableLeietakere.tsx │ │ ├── marked │ │ │ ├── DemographicAnalysis.tsx │ │ │ ├── MarketSentiment.tsx │ │ │ └── MarketStatistics.tsx │ │ ├── regnskap │ │ │ ├── ChartMainAccouting.tsx │ │ │ ├── KpiAccountCards.tsx │ │ │ ├── RegnskapsAnalyse.tsx │ │ │ └── TableAccounting.tsx │ │ ├── sampleProperties.ts │ │ ├── simulering │ │ │ ├── InvestmentParameters.tsx │ │ │ ├── KeyMetrics.tsx │ │ │ ├── MarketAnalysis.tsx │ │ │ ├── ScenarioComparison.tsx │ │ │ └── ScenarioManager.tsx │ │ └── workflow │ │ │ ├── generator.ts │ │ │ ├── schema.ts │ │ │ └── workflow-data.ts │ └── ui │ │ ├── Analycits-dashboard.tsx │ │ ├── Animated-Grid-Background.tsx │ │ ├── AnimatedCTA.tsx │ │ ├── ArrowAnimated.tsx │ │ ├── Benefits.tsx │ │ ├── CodeExample.tsx │ │ ├── CodeExampleTabs.tsx │ │ ├── CommandBar.tsx │ │ ├── Cta-middle.tsx │ │ ├── Cta.tsx │ │ ├── Display-chart-landing.tsx │ │ ├── DisplayCards.tsx │ │ ├── Divider.tsx │ │ ├── EarlyAccessCta.tsx │ │ ├── Fade.tsx │ │ ├── Faqs.tsx │ │ ├── FeatureDivider.tsx │ │ ├── Features.tsx │ │ ├── Features2.tsx │ │ ├── Footer.tsx │ │ ├── GlobalDatabase.tsx │ │ ├── Hero.tsx │ │ ├── Hero2.tsx │ │ ├── HeroBackground.tsx │ │ ├── HeroImage.tsx │ │ ├── InstaxImage.tsx │ │ ├── LineChartTjeneste.tsx │ │ ├── LogoCloud.tsx │ │ ├── Logos.tsx │ │ ├── Navbar.tsx │ │ ├── Searchbar.tsx │ │ ├── SideNav.tsx │ │ ├── TeamGallery.tsx │ │ ├── Testimonial.tsx │ │ ├── ThemedImage.tsx │ │ ├── button.tsx │ │ └── data-table │ │ ├── DataTable.tsx │ │ ├── DataTableBulkEditor.tsx │ │ ├── DataTableColumnHeader.tsx │ │ ├── DataTableFilter.tsx │ │ ├── DataTableFilterbar.tsx │ │ ├── DataTablePagination.tsx │ │ ├── DataTableRowActions.tsx │ │ ├── DataTableViewOptions.tsx │ │ ├── PropertyComparisonDrawer.tsx │ │ ├── PropertyDrawer.tsx │ │ ├── TanstackTable.d.ts │ │ └── columns.tsx ├── content │ ├── blog │ │ ├── fremtiden-for-naringseiendom.mdx │ │ ├── introduserer-propdock.mdx │ │ ├── kunnskapsbase.mdx │ │ └── slik-analyserer-du-eiendomsmarkedet.mdx │ ├── changelog │ │ └── tastatursnarveier.mdx │ ├── customers │ │ └── corponor.mdx │ ├── docs │ │ └── sample.mdx │ ├── help │ │ ├── diskontert-kontantstrom.mdx │ │ ├── driftskostnader.mdx │ │ ├── felleskostnader.mdx │ │ ├── hva-er-propdock.mdx │ │ ├── hva-er-yield.mdx │ │ ├── kontantstromsanalyse.mdx │ │ ├── markedsleie-og-leieniva.mdx │ │ ├── netto-leieinntekter.mdx │ │ ├── sensitivitetsanalyse.mdx │ │ ├── tjene-mer-pa-naringseiendom.mdx │ │ └── verdivurdering-av-naringseiendom.mdx │ ├── integrations │ │ ├── brreg.mdx │ │ └── kartverket.mdx │ └── legal │ │ ├── privacy.mdx │ │ └── terms.mdx ├── lib │ ├── actions.ts │ ├── blog │ │ ├── blur-image.tsx │ │ ├── content.tsx │ │ ├── images.ts │ │ └── use-current-anchor.ts │ ├── chartUtils.ts │ ├── coordinateUtils.ts │ ├── formatters.ts │ ├── hooks │ │ ├── use-debounce.ts │ │ ├── use-media-query.ts │ │ └── use-window-size.ts │ ├── use-scroll.ts │ ├── useOnWindowResize.ts │ └── utils.ts ├── middleware.ts └── types │ └── simulation.ts ├── tailwind.config.ts └── tsconfig.json /.content-collections/generated/allMarketReports.js: -------------------------------------------------------------------------------- 1 | 2 | export default [] -------------------------------------------------------------------------------- /.content-collections/generated/allPropertyPosts.js: -------------------------------------------------------------------------------- 1 | 2 | export default [] -------------------------------------------------------------------------------- /.content-collections/generated/index.d.ts: -------------------------------------------------------------------------------- 1 | import configuration from "../../content-collections.ts"; 2 | import { GetTypeByName } from "@content-collections/core"; 3 | 4 | export type BlogPost = GetTypeByName; 5 | export declare const allBlogPosts: Array; 6 | 7 | export type ChangelogPost = GetTypeByName; 8 | export declare const allChangelogPosts: Array; 9 | 10 | export type CustomersPost = GetTypeByName; 11 | export declare const allCustomersPosts: Array; 12 | 13 | export type HelpPost = GetTypeByName; 14 | export declare const allHelpPosts: Array; 15 | 16 | export type LegalPost = GetTypeByName; 17 | export declare const allLegalPosts: Array; 18 | 19 | export type IntegrationsPost = GetTypeByName; 20 | export declare const allIntegrationsPosts: Array; 21 | 22 | export {}; 23 | -------------------------------------------------------------------------------- /.content-collections/generated/index.js: -------------------------------------------------------------------------------- 1 | // generated by content-collections at Mon Mar 03 2025 20:21:03 GMT+0100 (GMT+01:00) 2 | 3 | import allBlogPosts from "./allBlogPosts.js"; 4 | import allChangelogPosts from "./allChangelogPosts.js"; 5 | import allCustomersPosts from "./allCustomersPosts.js"; 6 | import allHelpPosts from "./allHelpPosts.js"; 7 | import allLegalPosts from "./allLegalPosts.js"; 8 | import allIntegrationsPosts from "./allIntegrationsPosts.js"; 9 | 10 | export { allBlogPosts, allChangelogPosts, allCustomersPosts, allHelpPosts, allLegalPosts, allIntegrationsPosts }; 11 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | .cursor 40 | 41 | # content collections 42 | .content-collections/ 43 | .content-collections/cache/ 44 | .content-collections/generated/ 45 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "singleQuote": false, 4 | "trailingComma": "all", 5 | "endOfLine": "lf", 6 | "semi": false, 7 | "tabWidth": 2, 8 | "plugins": ["prettier-plugin-tailwindcss"], 9 | "tailwindFunctions": ["tv", "cx"] 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "tailwindCSS.experimental.classRegex": [ 3 | ["clsx\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], 4 | ["cx\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] 5 | ], 6 | "editor.formatOnSave": true, 7 | "editor.codeActionsOnSave": { 8 | "source.organizeImports": "explicit" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | import { withContentCollections } from "@content-collections/next"; 3 | import createMDX from "@next/mdx"; 4 | 5 | /** @type {import('next').NextConfig} */ 6 | const nextConfig = { 7 | // Configure `pageExtensions` to include markdown and MDX files 8 | pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"], 9 | // Optionally, add any other Next.js config below 10 | eslint: { ignoreDuringBuilds: true }, 11 | typescript: { ignoreBuildErrors: true }, 12 | images: { 13 | remotePatterns: [ 14 | { 15 | protocol: "https", 16 | hostname: "imagedelivery.net", 17 | port: "", 18 | pathname: "/**", 19 | }, 20 | { 21 | protocol: "https", 22 | hostname: "avatar.vercel.sh", 23 | port: "", 24 | pathname: "/**", 25 | }, 26 | { 27 | protocol: "https", 28 | hostname: "randomuser.me", 29 | port: "", 30 | pathname: "/**", 31 | }, 32 | ], 33 | }, 34 | } 35 | 36 | const withMDX = createMDX({ 37 | // Add markdown plugins here, as desired 38 | }) 39 | 40 | // Merge MDX config with Next.js config and Content Collections 41 | export default withContentCollections(withMDX(nextConfig)); 42 | 43 | 44 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | } 7 | 8 | export default config 9 | -------------------------------------------------------------------------------- /public/_static/integrasjoner/fiken.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/blocks.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/changelog/v316.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/changelog/v316.webp -------------------------------------------------------------------------------- /public/changelog/v317.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/changelog/v317.webp -------------------------------------------------------------------------------- /public/fonts/NanumPenScript.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/fonts/NanumPenScript.woff2 -------------------------------------------------------------------------------- /public/images/break.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/break.webp -------------------------------------------------------------------------------- /public/images/cool.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/cool.webp -------------------------------------------------------------------------------- /public/images/founders.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/founders.webp -------------------------------------------------------------------------------- /public/images/hero-dark.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/hero-dark.webp -------------------------------------------------------------------------------- /public/images/hero-light.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/hero-light.webp -------------------------------------------------------------------------------- /public/images/home.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/home.webp -------------------------------------------------------------------------------- /public/images/release.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/release.webp -------------------------------------------------------------------------------- /public/images/testimonial.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/testimonial.webp -------------------------------------------------------------------------------- /public/images/working.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/working.webp -------------------------------------------------------------------------------- /public/images/workplace.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/images/workplace.webp -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Propdock", 3 | "short_name": "Propdock", 4 | "description": "Intelligent verdsettelse og verdivurdering av næringseiendom", 5 | "start_url": "/", 6 | "display": "standalone", 7 | "background_color": "#1A1A1A", 8 | "theme_color": "#1A1A1A", 9 | "orientation": "portrait-primary", 10 | "icons": [ 11 | { 12 | "src": "/icon-192x192.png", 13 | "sizes": "192x192", 14 | "type": "image/png", 15 | "purpose": "any maskable" 16 | }, 17 | { 18 | "src": "/icon-512x512.png", 19 | "sizes": "512x512", 20 | "type": "image/png", 21 | "purpose": "any maskable" 22 | } 23 | ], 24 | "lang": "nb-NO", 25 | "categories": ["business", "finance", "productivity"], 26 | "screenshots": [], 27 | "prefer_related_applications": false 28 | } -------------------------------------------------------------------------------- /public/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codehagen/propdock/ed9debdc0b8df4188d1dcd1d0ea25a71f32a7bb1/public/opengraph-image.png -------------------------------------------------------------------------------- /src/app/(blog)/blog/(index)/category/[slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import { allBlogPosts } from "content-collections" 2 | import { Metadata } from "next" 3 | import { notFound } from "next/navigation" 4 | 5 | import BlogCard from "@/components/blog/blog-card" 6 | import { BLOG_CATEGORIES } from "@/lib/blog/content" 7 | import { getBlurDataURL } from "@/lib/blog/images" 8 | import { constructMetadata } from "@/lib/utils" 9 | 10 | interface BlogPost { 11 | title: string 12 | summary: string 13 | publishedAt: string 14 | image: string 15 | author: string 16 | slug: string 17 | mdx?: string 18 | related?: string[] 19 | tableOfContents?: any 20 | images?: any 21 | tweetIds?: any 22 | githubRepos?: any 23 | categories?: string[] 24 | _meta?: any 25 | } 26 | 27 | interface BlogPostWithBlur extends BlogPost { 28 | blurDataURL: string 29 | } 30 | 31 | export async function generateStaticParams() { 32 | return BLOG_CATEGORIES.map((category) => ({ 33 | slug: category.slug, 34 | })) 35 | } 36 | 37 | export async function generateMetadata({ 38 | params, 39 | }: { 40 | params: { slug: string } 41 | }): Promise { 42 | const { slug } = await params 43 | const category = BLOG_CATEGORIES.find((category) => category.slug === slug) 44 | if (!category) { 45 | return 46 | } 47 | 48 | const { title, description } = category 49 | 50 | return constructMetadata({ 51 | title: `${title} – Propdock`, 52 | description, 53 | image: `/api/og/help?title=${encodeURIComponent( 54 | title, 55 | )}&summary=${encodeURIComponent(description)}`, 56 | }) 57 | } 58 | 59 | export default async function BlogCategory({ 60 | params, 61 | }: { 62 | params: { 63 | slug: string 64 | } 65 | }) { 66 | const { slug } = await params 67 | const data = BLOG_CATEGORIES.find((category) => category.slug === slug) 68 | if (!data) { 69 | notFound() 70 | } 71 | 72 | const articles: BlogPostWithBlur[] = await Promise.all( 73 | allBlogPosts 74 | .filter((post) => post.categories?.includes(data.slug as any)) 75 | .sort((a, b) => b.publishedAt.localeCompare(a.publishedAt)) 76 | .map(async (post) => ({ 77 | title: post.title, 78 | summary: post.summary, 79 | publishedAt: post.publishedAt, 80 | image: post.image, 81 | author: post.author, 82 | slug: post.slug, 83 | categories: post.categories, 84 | blurDataURL: await getBlurDataURL(post.image), 85 | })), 86 | ) 87 | 88 | return articles.map((article, idx) => ( 89 | 90 | )) 91 | } 92 | -------------------------------------------------------------------------------- /src/app/(blog)/blog/(index)/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from "react" 2 | 3 | import BlogLayoutHero from "@/components/blog/blog-layout-hero" 4 | import MaxWidthWrapper from "@/components/blog/max-width-wrapper" 5 | 6 | // import Header from "@/components/sections/header"; 7 | // import Footer from "@/components/sections/footer"; 8 | 9 | export default async function BlogLayout({ 10 | children, 11 | }: { 12 | children: ReactNode 13 | }) { 14 | return ( 15 |
16 | {/*
*/} 17 |
18 | 19 |
20 | 21 | {children} 22 | 23 |
24 |
25 | {/*
*/} 26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/app/(blog)/blog/(index)/page.tsx: -------------------------------------------------------------------------------- 1 | import { allBlogPosts } from "content-collections" 2 | 3 | import BlogCard from "@/components/blog/blog-card" 4 | import { getBlurDataURL } from "@/lib/blog/images" 5 | import { constructMetadata } from "@/lib/utils" 6 | 7 | export const metadata = constructMetadata({ 8 | title: "Blog – Propdock", 9 | description: 10 | "Siste nyheter, trends og innsikter fra Propdock. Finn ekspertråd og veiledning for å forvalte og investere i næringseiendom.", 11 | }) 12 | 13 | export default async function Blog() { 14 | const articles = await Promise.all( 15 | allBlogPosts 16 | .sort( 17 | (a, b) => 18 | new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime(), 19 | ) 20 | .map(async (post) => ({ 21 | title: post.title, 22 | summary: post.summary, 23 | publishedAt: post.publishedAt, 24 | image: post.image, 25 | author: post.author, 26 | slug: post.slug, 27 | categories: post.categories, 28 | blurDataURL: await getBlurDataURL(post.image), 29 | })), 30 | ) 31 | 32 | return articles.map((article, idx) => ( 33 | 34 | )) 35 | } 36 | -------------------------------------------------------------------------------- /src/app/(blog)/blog/(post)/[slug]/layout.tsx: -------------------------------------------------------------------------------- 1 | interface MarketingLayoutProps { 2 | children: React.ReactNode 3 | } 4 | 5 | export default async function Layout({ children }: MarketingLayoutProps) { 6 | return ( 7 | <> 8 | {/*
*/} 9 |
{children}
10 | {/*