Statslegacy twin of sections/Stats

apps/www/src/components/Stats.astro · 159 lines · group Stats

Used by

Live sites: skattedosan.se.

Samples 2

skattedosan.se/en/
Introducing the next generation of Control Units

With Control Server Solution, there's no longer a need for the Tax Agency to physically visit your point of sale in order to download fiscal data.

Douglas Oest, Axena Company Service AB, CEO

Introducing the next generation of Control Units

We have introduced an innovative approach to processing fiscal data, featuring the latest hardware generation that securely signs and stores fiscal data. Additionally, our Control Unit replicates data to the server and can be seamlessly connected to the local network, supporting multiple cash registers.

MDX of this sample
<Stats
    title="Introducing the next generation of Control Units"
    text={[
        `We have introduced an innovative approach to processing fiscal data, featuring the latest hardware generation that securely signs and stores fiscal data. Additionally, our Control Unit replicates data to the server and can be seamlessly connected to the local network, supporting multiple cash registers.`
    ]}
    linkTitle="Know more"
    imageName = "cash_reg.jpg"
    citation = "With Control Server Solution, there's no longer a need for the Tax Agency to physically visit your point of sale in order to download fiscal data."
    citationSource = "Douglas Oest, Axena Company Service AB, CEO"
    primaryButtonTitle = 'Contact us'
    primaryButtonLink = '/en/contacts/'
    secondaryButtonTitle = 'Know more...'
    secondaryButtonLink = '/en/models/buffering-unit/'
/>
skattedosan.se/history: commit 1396f74 (2026-08-18)
Introducing the next generation of Control Units

With Control Server Solution, there's no longer a need for the Tax Agency to physically visit your point of sale in order to download fiscal data.

Douglas Oest, Axena Company Service AB, CEO

Introducing the next generation of Control Units

We have introduced an innovative approach to processing fiscal data, featuring the latest hardware generation that securely signs and stores fiscal data. Additionally, our Control Unit replicates data to the server and can be seamlessly connected to the local network, supporting multiple cash registers.

MDX of this sample
<Stats
    title="Introducing the next generation of Control Units"
    text={[
        `We have introduced an innovative approach to processing fiscal data, featuring the latest hardware generation that securely signs and stores fiscal data. Additionally, our Control Unit replicates data to the server and can be seamlessly connected to the local network, supporting multiple cash registers.`
    ]}
    linkTitle="Know more"
    imageName = "cash_reg.jpg"
    citation = "With Control Server Solution, there's no longer a need for the Tax Agency to physically visit your point of sale in order to download fiscal data."
    citationSource = "Douglas Oest, Axena Company Service AB, CEO"
    primaryButtonTitle = 'Contact us'
    primaryButtonLink = '/en/contacts/'
    secondaryButtonTitle = 'Know more...'
    secondaryButtonLink = '/en/models/buffering-unit/'
/>

Props

NameTypeRequiredDefaultDescription
statsStatisticItem[]yes[]
titlestringyes
textstring | string[]yes
linkTitlestringyes
imageNamestringyes
citationstringyes
citationSourcestring
primaryButtonTitlestring'Kontakta oss'
primaryButtonLinkstring'/contacts/'
secondaryButtonTitlestring'Buffertenhet'
secondaryButtonLinkstring'/models/buffering-unit/'

Source apps/www/src/components/Stats.astro @ gitt.one

---
import { Image } from 'astro:assets';
import { resolveImage } from '../lib/images';

interface StatisticItem {
  label: string;
  value: string;
}

interface Props {
  stats: StatisticItem[];
  title: string;
  text: string | string[];
  linkTitle: string;
  imageName: string;
  citation: string;
  citationSource?: string;
  primaryButtonTitle?: string;
  primaryButtonLink?: string;
  secondaryButtonTitle?: string;
  secondaryButtonLink?: string;
}

const {
  stats = [],
  title,
  text,
  linkTitle,
  imageName,
  citation,
  citationSource,
  primaryButtonTitle = 'Kontakta oss',
  primaryButtonLink = '/contacts/',
  secondaryButtonTitle = 'Buffertenhet',
  secondaryButtonLink = '/models/buffering-unit/',
} = Astro.props;

const image = await resolveImage(imageName);
const textItems = Array.isArray(text) ? text : [text];
---

<section class="relative mt-20">
  <div class="items-center lg:mx-auto lg:grid lg:max-w-7xl lg:grid-cols-2 lg:gap-24 lg:px-8">
    <div class="relative sm:py-16 lg:py-0">
      <div aria-hidden="true" class="hidden sm:block lg:absolute lg:inset-y-0 lg:right-0 lg:w-screen">
        <div class="absolute inset-y-0 right-1/2 w-full rounded-r-3xl bg-gray-50 lg:right-72"></div>
        <svg
          class="absolute left-1/2 top-8 -ml-3 lg:-right-8 lg:left-auto lg:top-12"
          width={404}
          height={392}
          fill="none"
          viewBox="0 0 404 392"
        >
          <defs>
            <pattern
              id="stats-dots-pattern"
              x={0}
              y={0}
              width={20}
              height={20}
              patternUnits="userSpaceOnUse"
            >
              <rect x={0} y={0} width={4} height={4} class="text-gray-200" fill="currentColor"></rect>
            </pattern>
          </defs>
          <rect width={404} height={392} fill="url(#stats-dots-pattern)"></rect>
        </svg>
      </div>
      <div class="relative mx-auto max-w-md px-4 sm:max-w-3xl sm:px-6 lg:max-w-none lg:px-0 lg:py-20">
        <!-- Testimonial card -->
        <div class="relative overflow-hidden rounded-2xl pb-10 pt-64 shadow-xl">
          <Image
            src={image}
            alt={title}
            widths={[400, 840]}
            class="absolute inset-0 h-full w-full object-cover"
          />
          <div class="relative bg-primary-700 px-8 py-4 text-white opacity-90">
            <blockquote>
              <div class="relative text-lg font-medium md:flex-grow">
                <svg
                  class="absolute left-0 top-0 h-8 w-8 -translate-x-3 -translate-y-2 transform"
                  fill="currentColor"
                  viewBox="0 0 32 32"
                  aria-hidden="true"
                >
                  <path
                    d="M9.352 4C4.456 7.456 1 13.12 1 19.36c0 5.088 3.072 8.064 6.624 8.064 3.36 0 5.856-2.688 5.856-5.856 0-3.168-2.208-5.472-5.088-5.472-.576 0-1.344.096-1.536.192.48-3.264 3.552-7.104 6.624-9.024L9.352 4zm16.512 0c-4.8 3.456-8.256 9.12-8.256 15.36 0 5.088 3.072 8.064 6.624 8.064 3.264 0 5.856-2.688 5.856-5.856 0-3.168-2.304-5.472-5.184-5.472-.576 0-1.248.096-1.44.192.48-3.264 3.456-7.104 6.528-9.024L25.864 4z"
                  ></path>
                </svg>
                <p class="relative indent-8">{citation}</p>
              </div>
              {citationSource && <p class="mt-4 font-semibold">{citationSource}</p>}
            </blockquote>
          </div>
        </div>
      </div>
    </div>

    <div class="relative mx-auto max-w-md px-4 sm:max-w-3xl sm:px-6 lg:px-0">
      <div class="pt-12 sm:pt-16 lg:pt-20">
        <h2 class="text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl">
          {title}
        </h2>
        <div class="mt-6 space-y-6 text-gray-500">
          {
            textItems.map((content, index) =>
              index === 0 ? (
                <p class="text-center text-lg">{content}</p>
              ) : (
                <p class="text-base leading-7">{content}</p>
              ),
            )
          }
        </div>
      </div>

      {
        stats.length > 0 && (
          <div class="mt-10">
            <div class="grid grid-cols-2 gap-x-4 gap-y-8">
              {stats.map((stat) => (
                <dl class="border-t-2 border-gray-100 pt-6">
                  <dt class="text-base font-medium text-gray-500">{stat.label}</dt>
                  <dd class="text-3xl font-extrabold tracking-tight text-gray-900">{stat.value}</dd>
                </dl>
              ))}
            </div>
            <div class="mt-10">
              <a href="#" class="text-base font-medium text-primary-500">
                {linkTitle}&nbsp;&rarr;
              </a>
            </div>
          </div>
        )
      }

      <div class="mt-10 sm:flex sm:justify-center lg:justify-start">
        <div class="rounded-md shadow">
          <a
            href={primaryButtonLink}
            class="flex w-full items-center justify-center whitespace-nowrap rounded-md border border-transparent bg-primary-600 px-8 py-3 text-base font-medium text-white hover:bg-primary-700 md:px-10 md:py-4 md:text-lg"
          >
            {primaryButtonTitle}
          </a>
        </div>
        <div class="mt-3 rounded-md shadow sm:ml-3 sm:mt-0">
          <a
            href={secondaryButtonLink}
            class="flex w-full items-center justify-center whitespace-nowrap rounded-md border border-transparent bg-white px-8 py-3 text-base font-medium text-primary-600 hover:bg-gray-50 md:px-10 md:py-4 md:text-lg"
          >
            {secondaryButtonTitle}
          </a>
        </div>
      </div>
    </div>
  </div>
</section>

Source links point to engine-astro@e857a859. Samples are cut from the sites' own content by scripts/gallery-extract.mjs; nothing is merged or removed yet.