esen_seo 0.8.0 copy "esen_seo: ^0.8.0" to clipboard
esen_seo: ^0.8.0 copied to clipboard

Real semantic HTML for Flutter Web — SEO widget extensions, meta tags, OpenGraph, JSON-LD and a bot-aware SSR server. No Puppeteer, pure Dart.

example/lib/main.dart

import 'package:esen_seo/esen_seo.dart';
import 'package:flutter/material.dart';

import 'docs_page.dart';
import 'seo_routes.dart';
import 'widgets.dart';

void main() {
  // cleanUrls: Path-URLs (/demo) statt Hash-Fragmente (/#/demo) —
  // Crawler ignorieren Fragmente. Der SeoRouteObserver unten setzt die
  // Meta-Daten pro Route automatisch aus der geteilten Tabelle.
  EsenSeo.init(cleanUrls: true);
  runApp(const EsenSeoExampleApp());
}

final Map<String, WidgetBuilder> _pages = {
  '/': (_) => const HomePage(),
  '/demo': (_) => const DemoPage(),
  '/docs': (_) => const DocsPage(),
};

class EsenSeoExampleApp extends StatelessWidget {
  const EsenSeoExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'esen_seo Example',
      theme: ThemeData(colorSchemeSeed: Colors.teal, useMaterial3: true),
      // Wendet bei jeder Navigation die Meta-Daten der passenden
      // SeoRoute an — kein EsenSeo.setMeta() pro Seite nötig.
      navigatorObservers: [
        SeoRouteObserver(routes: seoRoutes, canonicalBase: siteBase),
      ],
      initialRoute: '/',
      // Statische Hosts liefern Deep-Links gern mit Trailing Slash aus
      // (/docs → /docs/). normalizeSeoPath macht die App tolerant, sonst
      // fiele die Route auf '/' zurück.
      onGenerateRoute: (settings) {
        final name = normalizeSeoPath(settings.name ?? '/');
        final builder = _pages[name] ?? _pages['/']!;
        return MaterialPageRoute(
          builder: builder,
          settings: RouteSettings(name: name, arguments: settings.arguments),
        );
      },
    );
  }
}

// ---------------------------------------------------------------------------
// SEITE 1 — Home ('/')
// ---------------------------------------------------------------------------

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final textTheme = Theme.of(context).textTheme;

    return PageScaffold(
      // .main → <main>: der Hauptinhalt der Seite, einmal pro Seite.
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        spacing: 20,
        children: [
          // .h1 → <h1>: die Hauptüberschrift (Kurzform von
          // .seo(SeoTextTag.h1)).
          Text('Real SEO for Flutter Web', style: textTheme.displaySmall).h1,
          // .p → <p>: ein normaler Absatz.
          Text(
            'No Puppeteer. No tricks. Pure Dart.',
            style: textTheme.titleLarge,
          ).p,

          // .ul + .li → <ul><li>…</li></ul>: eine echte HTML-Liste.
          const Bullets([
            'Semantic HTML — h1 to h6, p, section...',
            'Meta Tags, OpenGraph, Twitter Cards',
            'Schema.org JSON-LD',
            'Bot-aware SSR Server — pure Dart',
            'Static prerendering — no server needed',
            'Smart Defaults — page never breaks',
          ]),

          // Image().seo(...) → <img src="..." alt="..." width="800"
          // height="400" loading="lazy"/>. Explizite Dimensionen helfen
          // Crawlern beim Layout (Core Web Vitals: CLS); ohne alt würde
          // das semanticLabel übernommen.
          ClipRRect(
            borderRadius: BorderRadius.circular(12),
            child: Image.network(
              'https://picsum.photos/800/400',
              semanticLabel: 'Demo Image',
              errorBuilder: (context, error, stack) => const SizedBox.shrink(),
            ).seo(
              alt: 'esen_seo demo image',
              width: 800,
              height: 400,
              lazy: true,
            ),
          ),

          // .section → <section>: gruppiert Überschrift + Inhalt.
          const DocSection(
            title: 'About',
            children: [
              Para(
                'esen_seo mirrors your Flutter widget tree as clean '
                'semantic HTML — right in the DOM, without Puppeteer or '
                'headless Chrome.',
              ),
            ],
          ),

          DocSection(
            title: 'How it works',
            children: [
              const Para('Add .seo() to your widgets:'),
              const Bullets([
                'Text widgets become h1, h2, p...',
                'Images become img with alt text',
                'Columns become div, section, article...',
                'GestureDetectors become anchor links',
              ]),
              // Interner Link: für den User Flutter-Navigation, für
              // Bots ein <a href>. Der SeoRouteObserver setzt beim
              // Navigieren automatisch die Meta-Daten der Ziel-Route.
              SeoLink(
                label: 'Read the full documentation →',
                href: '/docs',
                onTap: () => Navigator.pushNamed(context, '/docs'),
              ),
            ],
          ),
        ],
      ).main,
    );
  }
}

// ---------------------------------------------------------------------------
// SEITE 2 — Demo ('/demo')
// ---------------------------------------------------------------------------

class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    final textTheme = Theme.of(context).textTheme;

    return PageScaffold(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        spacing: 20,
        children: [
          Text('Live Demo', style: textTheme.displaySmall).h1,
          const Para(
            'Open DevTools → Elements to see the semantic HTML tree '
            'in #esen-seo-content.',
          ),
          const DocSection(
            title: 'Shorthand Tags',
            children: [
              Para('These are all shorthand getters:'),
              Bullets([
                '.h1 through .h6',
                '.p for paragraphs',
                '.li for list items',
                '.section .article .nav',
              ]),
            ],
          ),
          const DocSection(
            title: 'Schema.org JSON-LD',
            children: [
              Para(
                'This page has FAQ and BreadcrumbList schemas — check '
                'the page source.',
              ),
            ],
          ),
        ],
      ).main,
    );
  }
}
6
likes
0
points
672
downloads

Publisher

verified publisheresen.software

Weekly Downloads

Real semantic HTML for Flutter Web — SEO widget extensions, meta tags, OpenGraph, JSON-LD and a bot-aware SSR server. No Puppeteer, pure Dart.

Repository (GitHub)
View/report issues

Topics

#seo #ssr #html #meta-tags #web

License

unknown (license)

Dependencies

flutter, flutter_web_plugins, shelf, web

More

Packages that depend on esen_seo