Website Screenshots

 

The website screenshot plugin

With the WebsiteScreenshotPlugin you can take screenshots of websites, save those screenshots as images, and then display those screenshots in your website.

An ideal use-case for this plugin is to create a "showcase" of your other websites, such as on a portfolio website.

Configure the plugin

Add the WebsiteScreenshotPlugin to your StaticShock pipeline and configure the size of the final output image.

Future<void> main(List<String> arguments) async {
  // Configure the static website generator.
  final staticShock = StaticShock()
    // ...existing configuration here...
    ..plugin(const WebsiteScreenshotsPlugin(
      outputWidth: 256,
    ));

  // Generate the static website.
  await staticShock.generateSite();
}

When building your website, a headless browser is launched to take screenshots of the websites you requested. The WebsiteScreenshotsPlugin has a default browser viewport size, but if you'd like a different viewport size, you can provide that as a plugin argument.

  ..plugin(const WebsiteScreenshotsPlugin(
    viewportSize: const ViewportSize(width: 720, height: 1280)
    outputWidth: 256,
  ));

Request screenshots directly

If you know what screenshots you want to take within your Dart code, you can specify those screenshots directly, during plugin configuration.

Future<void> main(List<String> arguments) async {
  // Configure the static website generator.
  final staticShock = StaticShock()
    // ...existing configuration here...
    ..plugin(const WebsiteScreenshotsPlugin(
      screenshots: {
        WebsiteScreenshot(
          id: "static_shock",
          url: Uri.parse("https://staticshock.io"),
          output: FileRelativePath("images/screenshots", "staticshock", "png"),
        ),
        WebsiteScreenshot(
          id: "flutter_bounty_hunters",
          url: Uri.parse("https://flutterbountyhunters.com"),
          output: FileRelativePath("images/screenshots", "fbh", "png"),
        ),
      },
      outputWidth: 256,
    ));

  // Generate the static website.
  await staticShock.generateSite();
}

The "id" of each screenshot is used to cache the screenshots between builds. Using the same "id" multiple times will result in later screenshots overwriting earlier screenshots in your request set.

Requesting screenshots from data files

It's often more convenient to request screenshots from _data.yaml files than it is from Dart code. Your website probably includes template code that wants to display your screenshots. Your template code uses the data index to access information. Therefore, declaring your screenshots in the data index gives you a direct connection to your template code.

You can define screenshots anywhere in your data that you choose. You're in charge of where it goes, how it's formatted, and how you load it into the website screenshot plugin.

The following is one example for how you might request screenshots from your data.

/_data.yaml

showcase:
  screenshots:
    -
      id: "staticshock_io"
      title: "Static Shock"
      url: "https://staticshock.io"
      output: "/images/screenshots/staticshock_io.png"
    -
      id: "superdeclarative_com"
      title: "SuperDeclarative!"
      url: "https://superdeclarative.com"
      output: "/images/screenshots/superdeclarative_com.png"
    -
      id: "flutterbountyhunters_com"
      title: "Flutter Bounty Hunters"
      url: "https://flutterbountyhunters.com"
      output: "/images/screenshots/flutterbountyhunters_com.png"

Given the aforementioned _data.yaml definition, configure the plugin so that it loads this data.

/bin/main.dart:

Future<void> main(List<String> arguments) async {
  // Configure the static website generator.
  final staticShock = StaticShock()
    // ...existing configuration here...
    ..plugin(const WebsiteScreenshotsPlugin(
      selector: (context) {
        final rootData = context.dataIndex.inheritDataForPath(DirectoryRelativePath("/"));
        final showcase = rootData['showcase'];
        if (showcase == null) {
          return {};
        }
        if (showcase is! Map<String, dynamic>) {
          return {};
        }

        final screenshots = <WebsiteScreenshot>{};
        final screenshotsYaml = showcase['screenshots'] as List<dynamic>;

        for (final screenshotYaml in screenshotsYaml) {
          screenshots.add(
            WebsiteScreenshot(
              id: screenshotYaml['id'],
              url: Uri.parse(screenshotYaml['url']),
              output: FileRelativePath.parse(screenshotYaml['output']),
            ),
          );
        }

        return screenshots;
      },
      outputWidth: 256,
    ));

  // Generate the static website.
  await staticShock.generateSite();
}

The plugin selector finds the screenshot requests in the data index and feeds them to the screenshot plugin. At this point, those screenshots will be generated and saved when the website is built.

However, the webpage template still needs to read this data and display the screenshots. Assume that a showcase is built on the index page.

/index.jinja:

<section style="max-width: 1200px; margin: auto; margin-bottom: 200px;">
  <h2 style="text-align: center; text-transform: uppercase;">Showcase</h2>
  <p style="text-align: center; color: rgba(255, 255, 255, 0.5);">My awesome websites.</p>
  <ul style="list-style-type: none; margin: 0; padding: 0; text-align: center;">
    {% for screenshot in showcase.screenshots %}
    <li style="display: inline-block; margin: 0; padding: 0;">
      <a href="{{ screenshot.url }}" target="_blank" title="{{ screenshot.title }}">
        <img src="{{ screenshot.output }}" style="display: inline-block; border-radius: 4px; margin: 16px;">
      </a>
    </li>
    {% endfor %}
  </ul>
</section>

With the template code above, the webpage now displays the screenshots that were taken by the plugin, and were declared in _data.yaml.

To see this approach in action, visit the Static Shock homepage