blueprints/gallery.html
2026-01-27 12:50:04 +00:00

1036 lines
51 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WordPress Blueprints Gallery</title>
<script type="module">
import { h, render, Component } from 'https://esm.sh/preact@10.19.3';
import { useState, useEffect } from 'https://esm.sh/preact@10.19.3/hooks';
window.h = h;
window.Component = Component;
window.useState = useState;
window.useEffect = useEffect;
window.render = render;
</script>
<script id="blueprint-data" type="application/json">{"blueprints/portfolio-vueo/blueprint.json":{"title":"Art Gallery","description":"An art gallery created with the Vueo theme.","author":"WordPress.com","categories":["Website","Personal"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/portfolio-vueo/screenshot.jpg","featured":true},"blueprints/brewcommerce/blueprint.json":{"title":"Coffee Shop","description":"A stylish WooCommerce coffee shop storefront with custom theme, products, and content.","author":"adamziel","categories":["WooCommerce","Store"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/e3183200f04bac17b650ef303be934a0be5fe957/blueprints/brewcommerce/screenshot.jpg","featured":true},"blueprints/friends-cors/blueprint.json":{"title":"Feed Reader with the Friends Plugin","description":"By using the Friends plugin, you can read feeds from the web in Playground, and even via ActivityPub","author":"akirk","categories":["rss","social web"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/friends-cors/screenshot.jpg","featured":true},"blueprints/news-spiel/blueprint.json":{"title":"Gaming News","description":"A gaming news site created with the Spiel theme.","author":"WordPress.com","categories":["Website","News"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/news-spiel/screenshot.jpg","featured":true},"blueprints/organization-koinonia/blueprint.json":{"title":"Non-profit Organization","description":"A non-profit organization site created with the Koinonia theme.","author":"WordPress.com","categories":["Website","Organization"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/organization-koinonia/screenshot.jpg","featured":true},"blueprints/personal-substrata/blueprint.json":{"title":"Personal Blog","description":"A personal blog site created with the Substrata theme.","author":"WordPress.com","categories":["Website","Personal","Blog"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/personal-substrata/screenshot.jpg","featured":true},"blueprints/personal-readymade/blueprint.json":{"title":"Personal Resume","description":"A resume site created with the Readymade theme.","author":"WordPress.com","categories":["Website","Personal"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/personal-readymade/screenshot.jpg","featured":true},"blueprints/portfolio-grammer/blueprint.json":{"title":"Photography Portfolio","description":"A photography portfolio created with the Grammer theme.","author":"WordPress.com","categories":["Website","Personal","Photography"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/portfolio-grammer/screenshot.jpg","featured":true},"blueprints/news-piel/blueprint.json":{"title":"Skincare Blog","description":"A skincare blog created with the Piel theme.","author":"WordPress.com","categories":["Website","News","Blog"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/news-piel/screenshot.jpg","featured":true},"blueprints/organization-kentwood/blueprint.json":{"title":"University Website","description":"A university website created with the Kentwood theme.","author":"WordPress.com","categories":["Website","Organization","Education"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/organization-kentwood/screenshot.jpg","featured":true},"blueprints/create-block-theme/blueprint.json":{"title":"Create Block Theme","description":"Blueprint to install Create Block Theme and start editing right away","author":"jonathanbossenger","categories":["Editor","theme"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/create-block-theme/screenshot.jpg","featured":false},"blueprints/user-meta/blueprint.json":{"title":"Creating a new user for the blog","description":"This is a simple example to update user meta data","author":"fellyph","categories":["meta"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/user-meta/screenshot.jpg","featured":false},"blueprints/custom-post/blueprint.json":{"title":"Custom Post Type: Books","description":"Blueprint that added a custom post type to playground","author":"bph","categories":["Content","CPT"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/custom-post/screenshot.jpg","featured":false},"blueprints/tt5-demo/blueprint.json":{"title":"Demo of Twenty-Twenty-Five theme","description":"Blueprint with demo content for the Twenty-Twenty-Five default theme","author":"bph","categories":["Themes","default"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/tt5-demo/screenshot.jpg","featured":false},"blueprints/admin-notice/blueprint.json":{"title":"Display Admin Notice","description":"Blueprint to add a tiny mu-plugin and display an admin notice","author":"bph","categories":["Admin","notices"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/admin-notice/screenshot.jpg","featured":false},"blueprints/gb-more-experiments/blueprint.json":{"title":"Enable all three Dataview Experiments in Gutenberg","author":"bph","description":"Blueprint example to enable multiple Experiments within the Gutenberg plugin ","categories":["Gutenberg","Experiments"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/gb-more-experiments/screenshot.jpg","featured":false},"blueprints/fancy-dashboard_widget/blueprint.json":{"title":"Fancy Dashboard Widget","description":"A blueprint to display statistics about users, posts and comments on a WordPress site.","author":"muryamsultana","screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/fancy-dashboard_widget/screenshot.jpg","featured":false},"blueprints/grid-variations/blueprint.json":{"title":"Grid Variations Experiments enabled","author":"bph","description":"Blueprint example to toggle on enable a feature from the Experiments page in Gutenberg plugin","categories":["Gutenberg","Experiments"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/grid-variations/screenshot.jpg","featured":false},"blueprints/theme-starter-content/blueprint.json":{"title":"Import Theme Starter Content","author":"bph","description":"Blueprint to install a theme with starter content, (here: Twenty-Twenty-One)","categories":["Themes","Starter Content"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/theme-starter-content/screenshot.jpg","featured":false},"blueprints/file-starter-content/blueprint.json":{"title":"Import a standalone starter content via a blueprint step","author":"bph","description":"Blueprint to use a stand-alone starter content file and then to import it. Click on 'Subscriptions'","categories":["Themes","Starter Content"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/file-starter-content/screenshot.jpg","featured":false},"blueprints/translations/blueprint.json":{"title":"Install WordPress language packs","author":"adamziel","description":"Installs and activates the latest WordPress Japanese translation pack from https://translate.wordpress.org/ both for WordPress core and for the friends plugin.","categories":["core"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/translations/screenshot.jpg","featured":false},"blueprints/install-plugin-from-gist/blueprint.json":{"title":"Install plugin from a gist","author":"zieladam","description":"Install and activate a WordPress plugin from a .php file stored in a gist.","categories":["plugins"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/install-plugin-from-gist/screenshot.jpg","featured":false},"blueprints/latest-gutenberg/blueprint.json":{"title":"Latest Gutenberg plugin","author":"zieladam","description":"A preview of the latest version of the Gutenberg plugin.","categories":["plugins"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/latest-gutenberg/screenshot.jpg","featured":false},"blueprints/install-activate-setup-theme-from-gh-repo/blueprint.json":{"title":"Loading, activating, and configuring a theme from a GitHub repository.","description":"This is a good example of typical steps used on a theme's loading, activation and configuration","author":"richtabor","categories":["theme"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/install-activate-setup-theme-from-gh-repo/screenshot.jpg","featured":false},"blueprints/login-as-editor/blueprint.json":{"title":"Login as an editor","description":"Test WordPress functionality as an editor rather than an administrator.","author":"bacoords","categories":["User","Role"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/login-as-editor/screenshot.jpg","featured":false},"blueprints/blocky-formats/blueprint.json":{"title":"Markdown and Trac Syntax Editor","description":"Edit Markdown and Trac formatting in the block editor thanks to the blocky-formats plugin!","author":"adamziel","categories":["block-editor"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/blocky-formats/screenshot.jpg","featured":false},"blueprints/woo-shipping/blueprint.json":{"title":"Minimal WooCommerce Setup with Sample Products, Shipping, and Payment Method","description":"To create a WordPress Playground instance that installs WooCommerce, adds a custom flat rate shipping method via a plugin, imports WooCommerce sample products XML to demonstrate the shipping method on the cart/checkout pages, and enables the Direct Bank Transfer payment method.","author":"calvinrodrigues500","categories":["woocommerce","shipping","flat_rate"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/woo-shipping/screenshot.jpg","featured":false},"blueprints/my-wordpress/blueprint.json":{"title":"My WordPress","description":"A welcome experience for persistent WordPress Playground instances. Lets you personalize your site name and optionally import content from an RSS feed.","author":"Alex Kirk","categories":["Playground","Onboarding"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/caa7ea840c3e6707ee9f70deae73a7c37aa885ae/blueprints/my-wordpress/screenshot.jpg","featured":false},"blueprints/welcome/blueprint.json":{"title":"Playground Welcome Landing Page","description":"Landing page for the WordPress Playground giving a quick overview of the features and capabilities of the platform.","author":"fellyph","categories":["meta"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/welcome/screenshot.jpg","featured":false},"blueprints/use-pretty-permalinks/blueprint.json":{"title":"Pretty permalinks","description":"Set the permalink structure to use pretty permalinks.","author":"bgrgicak","categories":["Settings"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/use-pretty-permalinks/screenshot.jpg","featured":false},"blueprints/reset-data-and-import-content/blueprint.json":{"title":"Reset data and import content (with logs)","description":"It resets default data before importing custom content. It also logs the state of the content after each step.","author":"juanmaguitar","categories":["reset","log","debug","debug","import","content"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/reset-data-and-import-content/screenshot.jpg","featured":false},"blueprints/redirect-upload-requests/blueprint.json":{"title":"Serve media files from another host","description":"Redirect any requests to files within the uploads directory to an external host. This is useful when you have a lot of image attachments in your playground but dont want to include them all in the blueprint.","author":"ivanblagdan","categories":["Settings"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/redirect-upload-requests/screenshot.jpg","featured":false},"blueprints/set-admin-color-scheme/blueprint.json":{"title":"Set the admin color scheme","description":"Set the admin color scheme to Modern using the updateUserMeta step.","author":"ndiego","categories":["user meta"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/set-admin-color-scheme/screenshot.jpg","featured":false},"blueprints/showcase-plugin-with-media/blueprint.json":{"title":"Showcase plugin","description":"Showcase custom plugin from own server with media files and content imported as WXR. There is a readme file in github repository (https://github.com/Lovor01/blueprints/blob/trunk/blueprints/showcase-plugin-with-media/readme.md) which explains all steps.","author":"Lovor01","categories":["plugin","demo","media","images"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/showcase-plugin-with-media/screenshot.jpg","featured":false},"blueprints/stylish-press/blueprint.json":{"title":"Stylish Press","description":"A Woo store with custom theme, content, and products.","author":"adamziel","categories":["Woocommerce","Site"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/stylish-press/screenshot.jpg","featured":false},"blueprints/theme-a11y-test/blueprint.json":{"title":"Theme Tester","description":"Blueprint example to add content and plugins to explore a theme","author":"bph","categories":["themes","content"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/theme-a11y-test/screenshot.jpg","featured":false},"blueprints/wpgraphql/blueprint.json":{"title":"Use WPGraphQL to query WordPress","description":"Example that loads WordPress with WPGraphQL active and defaults to the WPGraphQL IDE page to allow users to test GraphQL queries and explore the GraphQL Schema.","author":"jasonbahl","categories":["API","wpgraphql"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/wpgraphql/screenshot.jpg","featured":false},"blueprints/posts-via-wp-cli/blueprint.json":{"title":"Use wp-cli command to add posts","description":"Blueprint example to add posts via a wp-cli command.","author":"bph","categories":["Content","wpcli"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/posts-via-wp-cli/screenshot.jpg","featured":false},"blueprints/wpcli-post-with-image/blueprint.json":{"title":"Use wp-cli to add a post with image","description":"Use wp-cli to create a post from text file with block markup and a featured image","author":"bph","categories":["Content","wpcli"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/wpcli-post-with-image/screenshot.jpg","featured":false},"blueprints/pwa-weather-app/blueprint.json":{"title":"Weather Shortcode Plugin","description":"A blueprint to connect weather API and show data as shortcode on a WordPress site. Requires your own OpenWeatherMap API key.","author":"muryamsultana","screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/pwa-weather-app/screenshot.jpg","featured":false},"blueprints/woocommerce-product-feed/blueprint.json":{"title":"WooCommerce product feed","description":"Blueprint to create a WooCommerce product and export an XML/CSV product feed","author":"mujuonly","categories":["WooCommerce","Content"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/woocommerce-product-feed/screenshot.jpg","featured":false},"blueprints/beta-rc/blueprint.json":{"title":"WordPress Beta","description":"Test the latest WordPress Beta or RC release with theme test data and debugging plugins. Only loads the Beta version during the Beta period.","author":"courtneyr-dev","categories":["Testing"],"screenshot_url":"https://raw.githubusercontent.com/wordpress/blueprints/c399585e8578db32a8706af8cfe25caf760c56cc/blueprints/beta-rc/screenshot.jpg","featured":false}}</script>
<style>
:root {
color-scheme: light;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
overflow-y: scroll;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
color: #1f2937;
background: #f3f4f6;
}
a {
color: inherit;
}
.page {
min-height: 100vh;
display: flex;
flex-direction: column;
background: #f3f4f6;
}
.hero {
background: #1f2937;
color: #f9fafb;
padding: 3rem 0 2.75rem;
box-shadow: 0 12px 40px rgba(15, 23, 42, 0.35);
}
.hero-inner {
max-width: 1200px;
margin: 0 auto;
padding: 0 2rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.hero-header {
display: flex;
align-items: center;
gap: 1rem;
}
.hero-logo {
width: 48px;
height: 48px;
}
.hero-title {
font-size: 2.25rem;
font-weight: 700;
margin: 0;
}
.hero-subtitle {
font-size: 1.05rem;
color: #d1d5db;
max-width: 820px;
line-height: 1.7;
}
.hero-link {
color: #60a5fa;
text-decoration: none;
font-weight: 600;
}
.hero-link:hover {
text-decoration: underline;
}
.filters-section {
background: #f9fafb;
border-bottom: 1px solid #e5e7eb;
}
.filters-inner {
max-width: 1200px;
margin: 0 auto;
padding: 1.75rem 2rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.tab-list {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
.tab {
padding: 0.6rem 1.2rem;
border-radius: 999px;
border: 1px solid #d1d5db;
background: #ffffff;
color: #1f2937;
font-weight: 600;
font-size: 0.95rem;
cursor: pointer;
transition: all 0.2s ease;
}
.tab:hover {
border-color: #94a3b8;
}
.tab.active {
background: #0f172a;
border-color: #0f172a;
color: #f9fafb;
box-shadow: 0 6px 16px rgba(15, 23, 42, 0.25);
}
.toolbar {
display: flex;
gap: 1rem;
align-items: center;
}
.search-block {
flex: 1;
max-width: 500px;
}
.search-field {
position: relative;
}
.search-field input {
width: 100%;
padding: 0.7rem 1rem 0.7rem 2.6rem;
border-radius: 12px;
border: 1px solid #d1d5db;
background: #ffffff;
font-size: 0.95rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.search-field input:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.search-icon {
position: absolute;
top: 50%;
left: 0.9rem;
transform: translateY(-50%);
color: #9ca3af;
font-size: 1.35rem;
pointer-events: none;
}
.gallery-section {
flex: 1;
}
.gallery-inner {
max-width: 1200px;
margin: 0 auto;
padding: 2rem 2rem 3rem;
}
.results-summary {
margin-bottom: 1.5rem;
color: #6b7280;
font-size: 0.95rem;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.75rem;
}
.skeleton-grid {
opacity: 0.9;
}
.pattern-card {
background: #ffffff;
border-radius: 4px;
overflow: hidden;
border: 1px solid #e5e7eb;
box-shadow: 0 15px 35px rgba(15, 23, 42, 0.08);
transition: transform 0.2s ease, box-shadow 0.2s ease;
display: flex;
flex-direction: column;
}
.pattern-card:hover {
transform: translateY(-4px);
box-shadow: 0 22px 45px rgba(15, 23, 42, 0.15);
}
.pattern-card-image {
display: block;
width: 100%;
height: 230px;
object-fit: cover;
object-position: center top;
background: #f3f4f6;
}
.pattern-card-image.placeholder {
display: flex;
align-items: center;
justify-content: center;
height: 230px;
font-size: 0.95rem;
color: #9ca3af;
}
.pattern-card-body {
padding: 1.25rem 1.5rem 1.4rem;
display: flex;
flex-direction: column;
gap: 0.9rem;
flex: 1;
}
.pattern-card-header {
display: flex;
align-items: flex-start;
gap: 0.75rem;
flex-wrap: nowrap;
}
.pattern-card-title {
margin: 0;
font-size: 1.05rem;
font-weight: 600;
color: #111827;
flex: 1 1 auto;
min-width: 0;
}
.pattern-card-description {
margin: 0;
font-size: 0.9rem;
color: #6b7280;
min-height: 2.4rem;
}
.pattern-card-meta {
margin: 0;
font-size: 0.85rem;
color: #6b7280;
margin-top: auto;
}
.pattern-card-meta a {
color: #2563eb;
text-decoration: none;
font-weight: 600;
}
.pattern-card-meta a:hover {
text-decoration: underline;
}
.pattern-card-meta .meta-separator {
color: #d1d5db;
margin: 0 0.25rem;
font-weight: 600;
}
.btn-try-it {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.65rem 1.25rem;
background: #3858e9;
color: #ffffff;
border-radius: 8px;
font-weight: 600;
font-size: 0.95rem;
text-decoration: none;
transition: background 0.2s ease, transform 0.1s ease;
flex-shrink: 0;
}
.pattern-card-header .btn-try-it {
margin-left: auto;
}
.btn-try-it:hover {
background: #2a44d0;
transform: translateY(-1px);
}
.btn-try-it .btn-icon {
width: 18px;
height: 18px;
}
.btn-view-source {
color: #6b7280;
font-weight: 600;
font-size: 0.9rem;
text-decoration: none;
}
.btn-view-source:hover {
color: #2563eb;
text-decoration: underline;
}
.empty-state {
margin-top: 3rem;
text-align: center;
padding: 3rem;
background: #ffffff;
border-radius: 16px;
border: 1px solid #e5e7eb;
color: #6b7280;
box-shadow: 0 15px 35px rgba(15, 23, 42, 0.08);
}
.empty-state h2 {
font-size: 1.6rem;
color: #111827;
margin-bottom: 0.75rem;
}
.placeholder-card {
background: #ffffff;
border-radius: 4px;
border: 1px solid #e5e7eb;
padding-bottom: 1.25rem;
box-shadow: 0 10px 25px rgba(15, 23, 42, 0.08);
display: flex;
flex-direction: column;
gap: 1rem;
}
.placeholder-thumb {
height: 230px;
background: #e5e7eb;
}
.placeholder-body {
padding: 0 1.5rem;
display: flex;
flex-direction: column;
gap: 0.7rem;
}
.placeholder-line {
height: 12px;
border-radius: 999px;
background: #e5e7eb;
}
.placeholder-line.wide {
width: 70%;
}
.placeholder-line.medium {
width: 55%;
}
.placeholder-line.short {
width: 40%;
}
.skeleton-animate {
position: relative;
overflow: hidden;
}
.skeleton-animate::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%);
transform: translateX(-100%);
animation: shimmer 1.4s infinite;
}
@keyframes shimmer {
100% {
transform: translateX(100%);
}
}
.no-results h2 {
font-size: 1.6rem;
color: #111827;
margin-bottom: 0.75rem;
}
.footer {
background: #f9fafb;
padding: 3rem 2rem 3.5rem;
color: #6b7280;
font-size: 0.9rem;
text-align: center;
border-top: 1px solid #e5e7eb;
}
.footer a {
color: #2563eb;
text-decoration: none;
font-weight: 600;
}
.footer a:hover {
text-decoration: underline;
}
@media (max-width: 960px) {
.global-nav-inner {
gap: 1rem;
}
.hero-title {
font-size: 2.4rem;
}
.toolbar {
flex-direction: column;
align-items: flex-start;
}
.dropdown-group {
width: 100%;
justify-content: flex-start;
}
.search-block {
width: 100%;
}
}
@media (max-width: 600px) {
.global-nav-inner {
padding: 0.65rem 1.25rem;
flex-direction: column;
align-items: flex-start;
gap: 0.75rem;
}
.hero-inner {
padding: 0 1.25rem;
}
.filters-inner {
padding: 1.5rem 1.25rem;
}
.gallery-inner {
padding: 1.5rem 1.25rem 2.5rem;
}
.tab {
padding: 0.5rem 1rem;
font-size: 0.9rem;
}
.pattern-card-body {
padding: 1rem 1.1rem 1.1rem;
}
.pattern-card-header {
align-items: center;
}
}
</style>
</head>
<body>
<div id="app"></div>
<script type="module">
const { h, render, useState, useEffect } = window;
const dataElement = document.getElementById('blueprint-data');
let embeddedIndex = null;
if (dataElement) {
try {
embeddedIndex = JSON.parse(dataElement.textContent || '{}');
} catch (error) {
console.error('Failed to parse embedded blueprint data.', error);
}
}
window.__EMBEDDED_BLUEPRINT_INDEX__ = embeddedIndex;
const highlightedBlueprints = [
'Stylish Press',
'Feed Reader with the Friends Plugin',
'Gaming News',
'Skincare Blog',
'Non-profit Organization',
'Personal Resume',
'Personal Blog',
'University Website',
'Photography Portfolio',
'Art Gallery'
];
function deriveBlueprintData(indexData) {
if (!indexData) {
return null;
}
const categoryCount = {};
const authors = new Set();
let highlightedTotal = 0;
const entries = Object.entries(indexData).map(([path, meta], index) => {
const categories = meta.categories || [];
categories.forEach(cat => {
categoryCount[cat] = (categoryCount[cat] || 0) + 1;
});
if (meta.author) {
authors.add(meta.author);
}
const isHighlighted = highlightedBlueprints.includes(meta.title);
if (isHighlighted) {
highlightedTotal += 1;
}
return {
path,
title: meta.title || 'Untitled Blueprint',
description: meta.description || '',
author: meta.author || '',
categories,
screenshot_url: meta.screenshot_url || '',
highlighted: isHighlighted,
order: index
};
});
const sortedCategories = Object.entries(categoryCount)
.sort((a, b) => b[1] - a[1])
.map(([name]) => name);
return {
entries,
topCategories: sortedCategories.slice(0, 8),
allCategories: sortedCategories,
stats: {
totalBlueprints: entries.length,
uniqueCategories: Object.keys(categoryCount).length,
uniqueAuthors: authors.size,
highlighted: highlightedTotal
}
};
}
const initialBlueprintData = deriveBlueprintData(embeddedIndex);
function buildPreviewUrl(path) {
return `https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/wordpress/blueprints/trunk/${path}`;
}
function buildEditUrl(path) {
return `https://playground.wordpress.net/builder/builder.html?blueprint-url=https://raw.githubusercontent.com/wordpress/blueprints/trunk/${path}`;
}
function buildSourceUrl(path) {
return `https://github.com/wordpress/blueprints/blob/trunk/${path}`;
}
function computeFavoriteCount(blueprint) {
const seed = `${blueprint.title}|${blueprint.path}`;
const hash = Array.from(seed).reduce((total, char) => total + char.charCodeAt(0), 0);
return 40 + (hash % 160);
}
function formatNumber(value) {
return value.toLocaleString('en-US');
}
function normalizeScreenshotSrc(blueprint) {
const rawPrefix = 'https://raw.githubusercontent.com/wordpress/blueprints/';
const { screenshot_url: originalSrc = '', path = '' } = blueprint;
if (originalSrc.startsWith(rawPrefix)) {
return originalSrc.replace(/^https:\/\/raw\.githubusercontent\.com\/wordpress\/blueprints\/[^/]+\//, '');
}
if (originalSrc) {
return originalSrc;
}
if (path) {
return path.replace(/blueprint\.json$/, 'screenshot.jpg');
}
return '';
}
function BlueprintCard({ blueprint }) {
const previewUrl = buildPreviewUrl(blueprint.path);
const sourceUrl = buildSourceUrl(blueprint.path);
const editUrl = buildEditUrl(blueprint.path);
const screenshotSrc = normalizeScreenshotSrc(blueprint);
const metaChildren = [];
if (blueprint.author) {
metaChildren.push('By ');
metaChildren.push(h('a', {
href: `https://github.com/${encodeURIComponent(blueprint.author)}`,
target: '_blank',
rel: 'noreferrer noopener'
}, `@${blueprint.author}`));
}
const sourceLink = h('a', {
href: sourceUrl,
target: '_blank',
rel: 'noreferrer noopener'
}, 'View source');
const editLink = h('a', {
href: editUrl,
target: '_blank',
rel: 'noreferrer noopener'
}, 'Edit');
const addSeparatorIfNeeded = () => {
if (metaChildren.length > 0) {
metaChildren.push(' ');
metaChildren.push(h('span', { className: 'meta-separator' }, '•'));
metaChildren.push(' ');
}
};
addSeparatorIfNeeded();
metaChildren.push(sourceLink);
addSeparatorIfNeeded();
metaChildren.push(editLink);
const metaLine = h('p', { className: 'pattern-card-meta' }, metaChildren);
return h('article', { className: 'pattern-card' },
screenshotSrc
? h('img', {
className: 'pattern-card-image',
src: screenshotSrc,
alt: `${blueprint.title} screenshot`,
onError: (event) => {
event.target.parentElement.innerHTML = '<div class="pattern-card-image placeholder">No screenshot available</div>';
}
})
: h('div', { className: 'pattern-card-image placeholder' }, 'No screenshot available'),
h('div', { className: 'pattern-card-body' },
h('div', { className: 'pattern-card-header' },
h('h2', { className: 'pattern-card-title' }, blueprint.title),
h('a', {
href: previewUrl,
className: 'btn-try-it',
target: '_blank',
rel: 'noreferrer noopener'
},
h('img', {
src: 'playground-icon.png',
className: 'btn-icon',
alt: ''
}),
'Run'
)
),
blueprint.description && h('p', { className: 'pattern-card-description' }, blueprint.description),
metaLine
)
);
}
function PlaceholderCard() {
return h('article', { className: 'placeholder-card' },
h('div', { className: 'placeholder-thumb skeleton-animate' }),
h('div', { className: 'placeholder-body' },
h('div', { className: 'placeholder-line wide skeleton-animate' }),
h('div', { className: 'placeholder-line medium skeleton-animate' }),
h('div', { className: 'placeholder-line short skeleton-animate' })
)
);
}
function App() {
const blueprintEntries = initialBlueprintData ? initialBlueprintData.entries : [];
const blueprints = blueprintEntries;
const topCategories = initialBlueprintData ? initialBlueprintData.topCategories : [];
const allCategories = initialBlueprintData ? initialBlueprintData.allCategories : [];
const stats = initialBlueprintData ? initialBlueprintData.stats : {
totalBlueprints: 0,
uniqueCategories: 0,
uniqueAuthors: 0,
highlighted: 0
};
const [filteredBlueprints, setFilteredBlueprints] = useState(blueprintEntries);
const [searchTerm, setSearchTerm] = useState('');
const [activeCategories, setActiveCategories] = useState(new Set());
const [showFeaturedOnly, setShowFeaturedOnly] = useState(false);
const [sortMode, setSortMode] = useState('gallery');
const [selectedFilter, setSelectedFilter] = useState('all');
const isLoaded = Boolean(initialBlueprintData);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const searchParam = params.get('search');
const categoriesParam = params.get('categories');
const featuredParam = params.get('featured');
const sortParam = params.get('sort');
const filterParam = params.get('filter');
if (searchParam) {
setSearchTerm(searchParam);
}
if (categoriesParam) {
const categoryList = categoriesParam.split(',').filter(Boolean);
if (categoryList.length > 0) {
setActiveCategories(new Set(categoryList));
setSelectedFilter(categoryList[0]);
}
}
if (featuredParam === 'true') {
setShowFeaturedOnly(true);
setSelectedFilter('featured');
}
if (sortParam) {
setSortMode(sortParam);
}
if (filterParam) {
setSelectedFilter(filterParam === 'curated' ? 'all' : filterParam);
}
}, []);
useEffect(() => {
if (!initialBlueprintData) {
console.error('Blueprint index data missing. Rebuild gallery.html to embed it.');
}
}, []);
useEffect(() => {
const params = new URLSearchParams();
if (searchTerm) {
params.set('search', searchTerm);
}
if (activeCategories.size > 0) {
params.set('categories', Array.from(activeCategories).join(','));
}
if (showFeaturedOnly) {
params.set('featured', 'true');
}
if (sortMode && sortMode !== 'gallery') {
params.set('sort', sortMode);
}
if (selectedFilter && selectedFilter !== 'all') {
params.set('filter', selectedFilter);
}
const newUrl = params.toString()
? `${window.location.pathname}?${params.toString()}`
: window.location.pathname;
window.history.replaceState({}, '', newUrl);
}, [searchTerm, activeCategories, showFeaturedOnly, sortMode, selectedFilter]);
useEffect(() => {
const term = searchTerm.trim().toLowerCase();
const filtered = blueprints.filter(bp => {
const matchesSearch = !term ||
bp.title.toLowerCase().includes(term) ||
bp.description.toLowerCase().includes(term) ||
bp.author.toLowerCase().includes(term);
const matchesCategory = activeCategories.size === 0 ||
bp.categories.some(cat => activeCategories.has(cat));
const matchesFeatured = !showFeaturedOnly || bp.highlighted;
return matchesSearch && matchesCategory && matchesFeatured;
});
const sorted = [...filtered];
if (sortMode === 'alphabetical') {
sorted.sort((a, b) => a.title.localeCompare(b.title));
} else if (sortMode === 'author') {
sorted.sort((a, b) =>
(a.author || '').localeCompare(b.author || '') || a.title.localeCompare(b.title)
);
} else if (sortMode === 'newest') {
sorted.sort((a, b) => b.path.localeCompare(a.path));
} else {
sorted.sort((a, b) => a.order - b.order);
}
setFilteredBlueprints(sorted);
}, [searchTerm, activeCategories, blueprints, showFeaturedOnly, sortMode]);
const navItems = ['News', 'Showcase', 'Hosting', 'Extend', 'Learn', 'Community', 'About'];
const baseTabs = ['All', 'Featured'];
const tabItems = Array.from(new Set([...baseTabs, ...topCategories.slice(0, 6)]));
const handleTabClick = (tab) => {
if (tab === 'All') {
setActiveCategories(new Set());
setShowFeaturedOnly(false);
setSelectedFilter('all');
return;
}
if (tab === 'Featured') {
setActiveCategories(new Set());
setShowFeaturedOnly(true);
setSelectedFilter('featured');
return;
}
setActiveCategories(new Set([tab]));
setShowFeaturedOnly(false);
setSelectedFilter(tab);
};
const handleFilterChange = (value) => {
if (value === 'curated' || value === 'all') {
setSelectedFilter('all');
setActiveCategories(new Set());
setShowFeaturedOnly(false);
return;
}
if (value === 'featured') {
setSelectedFilter('featured');
setActiveCategories(new Set());
setShowFeaturedOnly(true);
return;
}
setSelectedFilter(value);
setActiveCategories(new Set([value]));
setShowFeaturedOnly(false);
};
const handleFeaturedToggle = (event) => {
const checked = event.target.checked;
setShowFeaturedOnly(checked);
if (checked) {
setSelectedFilter('featured');
setActiveCategories(new Set());
} else if (selectedFilter === 'featured') {
setSelectedFilter('all');
}
};
const showingAll = selectedFilter === 'all' &&
filteredBlueprints.length === blueprints.length &&
activeCategories.size === 0 &&
!searchTerm &&
!showFeaturedOnly;
const isTabActive = (tab) => {
if (tab === 'All') {
return selectedFilter === 'all';
}
if (tab === 'Featured') {
return selectedFilter === 'featured';
}
return activeCategories.has(tab);
};
const resultsMessage = !isLoaded
? 'Loading blueprints...'
: showingAll
? `Showing all ${formatNumber(blueprints.length)} blueprints`
: `Showing ${formatNumber(filteredBlueprints.length)} of ${formatNumber(blueprints.length)} blueprints`;
const filterOptions = [
{ value: 'all', label: 'All blueprints' },
{ value: 'featured', label: 'Featured' },
...allCategories.map(cat => ({ value: cat, label: cat }))
];
const placeholderCards = Array.from({ length: 6 }).map((_, index) =>
h(PlaceholderCard, { key: `placeholder-${index}` })
);
const shouldShowSkeletons = !isLoaded;
const showEmptyState = isLoaded && filteredBlueprints.length === 0;
const emptyState = h('div', { className: 'empty-state' },
h('h2', null, 'No blueprints match your filters'),
h('p', null, 'Try adjusting your search terms or selecting a different category.')
);
const galleryContent = shouldShowSkeletons
? h('div', { className: 'gallery-grid skeleton-grid' }, placeholderCards)
: showEmptyState
? emptyState
: h('div', { className: 'gallery-grid' },
filteredBlueprints.map(bp =>
h(BlueprintCard, {
blueprint: bp,
key: bp.path
})
)
);
return h('div', { className: 'page' },
h('section', { className: 'hero' },
h('div', { className: 'hero-inner' },
h('div', { className: 'hero-header' },
h('img', {
src: 'playground-icon.png',
alt: 'WordPress Playground',
className: 'hero-logo'
}),
h('h1', { className: 'hero-title' }, 'WordPress Blueprints Gallery')
),
h('p', { className: 'hero-subtitle' },
'Launch ready-made WordPress environments in seconds. Browse community-created ',
h('a', {
href: 'https://wordpress.github.io/wordpress-playground/',
target: '_blank',
rel: 'noreferrer noopener',
className: 'hero-link'
}, 'WordPress Playground'),
' blueprints and discover pre-configured setups. Learn how to ',
h('a', {
href: 'https://wordpress.github.io/wordpress-playground/blueprints/tutorial/',
target: '_blank',
rel: 'noreferrer noopener',
className: 'hero-link'
}, 'create your own')
)
)
),
h('section', { className: 'filters-section' },
h('div', { className: 'filters-inner' },
h('div', { className: 'tab-list' },
tabItems.map(tab =>
h('button', {
key: tab,
className: `tab ${isTabActive(tab) ? 'active' : ''}`,
onClick: () => handleTabClick(tab)
}, tab)
)
),
h('div', { className: 'toolbar' },
h('div', { className: 'search-block' },
h('div', { className: 'search-field' },
h('span', { className: 'search-icon' }, '⌕'),
h('input', {
type: 'search',
placeholder: 'Search blueprints',
value: searchTerm,
onInput: (event) => setSearchTerm(event.target.value)
})
)
)
)
)
),
h('main', { className: 'gallery-section' },
h('div', { className: 'gallery-inner' },
h('div', { className: 'results-summary' }, resultsMessage),
galleryContent
)
),
h('footer', { className: 'footer' },
h('p', null,
'Want to contribute your own blueprint? Check out the ',
h('a', {
href: 'https://github.com/wordpress/blueprints/blob/trunk/README.md#contributing-your-blueprint',
target: '_blank',
rel: 'noreferrer noopener'
}, 'contribution guidelines')
),
h('p', { style: { marginTop: '1rem' } },
h('a', { href: 'https://github.com/wordpress/blueprints', target: '_blank' }, 'View on GitHub'),
' • ',
h('a', { href: 'https://github.com/wordpress/blueprints/blob/trunk/GALLERY.md', target: '_blank' }, 'View as Markdown')
)
)
);
}
setTimeout(() => {
if (window.h && window.render) {
render(h(App), document.getElementById('app'));
}
}, 100);
</script>
</body>
</html>