|
| 1 | +const fs = require('fs'); |
| 2 | +const path = require('path'); |
| 3 | +const examples = require('./examples') |
| 4 | + |
| 5 | +// Function to generate sidebar HTML |
| 6 | +const generateSidebarHtml = (sections) => { |
| 7 | + let sidebarHtml = '<div class="sidebar-content">'; |
| 8 | + |
| 9 | + sections.forEach(section => { |
| 10 | + sidebarHtml += `<div class="sidebar-category">`; |
| 11 | + sidebarHtml += `<div class="sidebar-category-title">${section.title}</div>`; |
| 12 | + section.children.forEach(example => { |
| 13 | + sidebarHtml += `<a href="/playground/${example.slug ? example.slug + '/' : ''}" class="sidebar-item">${example.title}</a>`; |
| 14 | + }); |
| 15 | + sidebarHtml += `</div>`; |
| 16 | + }); |
| 17 | + |
| 18 | + sidebarHtml += '</div>'; |
| 19 | + return sidebarHtml; |
| 20 | +}; |
| 21 | + |
| 22 | +const playgroundHtml = ` |
| 23 | +<html> |
| 24 | +
|
| 25 | +<head> |
| 26 | + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" |
| 27 | + integrity="sha512-NhSC1YmyruXifcj/KFRWoC561YpHpc5Jtzgvbuzx5VozKpWvQ+4nXhPdFgmx8xqexRcpAglTj9sIBWINXa8x5w==" |
| 28 | + crossorigin="anonymous" referrerpolicy="no-referrer" /> |
| 29 | + <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 30 | + <link href="https://fonts.googleapis.com/css?family=Roboto:black,bold,medium,regular,light,thin" rel="stylesheet"> |
| 31 | + <title>{{TITLE}}</title> |
| 32 | + <meta name="title" content="{{TITLE}}" /> |
| 33 | + <meta name="description" content="{{DESCRIPTION}}" /> |
| 34 | +
|
| 35 | + <link rel="canonical" href="{{CANONICAL}}"> |
| 36 | +
|
| 37 | + <meta property="og:title" content="{{TITLE}}"> |
| 38 | + <meta property="og:description" content="{{DESCRIPTION}}" /> |
| 39 | + <meta property="og:type" content="website" /> |
| 40 | + <meta name="og:image" content="https://assets.puter.site/twitter.png"> |
| 41 | + <meta name="og:url" content="{{CANONICAL}}"> |
| 42 | +
|
| 43 | + <meta name="twitter:card" content="summary_large_image" /> |
| 44 | + <meta name="twitter:site" content="@HeyPuter" /> |
| 45 | + <meta name="twitter:title" content="{{TITLE}}"> |
| 46 | + <meta name="twitter:description" content="{{DESCRIPTION}}" /> |
| 47 | + <meta name="twitter:image" content="https://assets.puter.site/twitter.png"> |
| 48 | +
|
| 49 | + <link rel="apple-touch-icon" sizes="57x57" href="/assets/favicon/apple-icon-57x57.png"> |
| 50 | + <link rel="apple-touch-icon" sizes="60x60" href="/assets/favicon/apple-icon-60x60.png"> |
| 51 | + <link rel="apple-touch-icon" sizes="72x72" href="/assets/favicon/apple-icon-72x72.png"> |
| 52 | + <link rel="apple-touch-icon" sizes="76x76" href="/assets/favicon/apple-icon-76x76.png"> |
| 53 | + <link rel="apple-touch-icon" sizes="114x114" href="/assets/favicon/apple-icon-114x114.png"> |
| 54 | + <link rel="apple-touch-icon" sizes="120x120" href="/assets/favicon/apple-icon-120x120.png"> |
| 55 | + <link rel="apple-touch-icon" sizes="144x144" href="/assets/favicon/apple-icon-144x144.png"> |
| 56 | + <link rel="apple-touch-icon" sizes="152x152" href="/assets/favicon/apple-icon-152x152.png"> |
| 57 | + <link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-icon-180x180.png"> |
| 58 | + <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicon/android-icon-192x192.png"> |
| 59 | + <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png"> |
| 60 | + <link rel="icon" type="image/png" sizes="96x96" href="/assets/favicon/favicon-96x96.png"> |
| 61 | + <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png"> |
| 62 | + <link rel="manifest" href="/assets/favicon/manifest.json"> |
| 63 | + <meta name="msapplication-TileColor" content="#ffffff"> |
| 64 | + <meta name="msapplication-TileImage" content="/assets/favicon/ms-icon-144x144.png"> |
| 65 | + <meta name="theme-color" content="#ffffff"> |
| 66 | + <script defer data-domain="docs.puter.com" src="https://plausible.io/js/script.js"></script> |
| 67 | + <link rel="stylesheet" href="/playground/assets/css/style.css"> |
| 68 | +</head> |
| 69 | +
|
| 70 | +<body> |
| 71 | + <script src="https://code.jquery.com/jquery-3.7.1.min.js" |
| 72 | + integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> |
| 73 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.min.js" |
| 74 | + integrity="sha512-ZG31AN9z/CQD1YDDAK4RUAvogwbJHv6bHrumrnMLzdCrVu4HeAqrUX7Jsal/cbUwXGfaMUNmQU04tQ8XXl5Znw==" |
| 75 | + crossorigin="anonymous" referrerpolicy="no-referrer"></script> |
| 76 | + <script src="https://js.puter.com/v2/"></script> |
| 77 | +
|
| 78 | + <div style="height: 50px; padding: 10px; background-color: #474e5d; display: flex; flex-direction: row;"> |
| 79 | + <h1 class="logo"><a href="/playground/">Puter.js Playground</a></h1> |
| 80 | + <div style="float:right;" class="navbar"> |
| 81 | + <a href="/" target="_blank" style="margin-right: 35px;">Docs</a> |
| 82 | + <a style="display: flex; flex-direction: row; align-items: center;" |
| 83 | + href="https://github.com/heyPuter/puter/" target="_blank"><svg role="img" |
| 84 | + style="margin-right:4px; margin-bottom: 3px;" width="17" height="17" viewBox="0 0 24 24" fill="#fff" |
| 85 | + xmlns="http://www.w3.org/2000/svg"> |
| 86 | + <title>GitHub</title> |
| 87 | + <path |
| 88 | + d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" /> |
| 89 | + </svg><span class="github-stars"></span></a></h1> |
| 90 | + </div> |
| 91 | + </div> |
| 92 | +
|
| 93 | + <div class="main-container"> |
| 94 | + <!-- Sidebar --> |
| 95 | + <div id="sidebar-container"> |
| 96 | + <div class="sidebar-header"> |
| 97 | + <button class="sidebar-toggle" id="sidebar-toggle"> |
| 98 | + <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-menu-icon lucide-menu"><path d="M4 5h16"/><path d="M4 12h16"/><path d="M4 19h16"/></svg> |
| 99 | + </button> |
| 100 | + <span class="sidebar-title">Examples</span> |
| 101 | + </div> |
| 102 | + <div class="sidebar"> |
| 103 | + {{SIDEBAR}} |
| 104 | + </div> |
| 105 | + </div> |
| 106 | +
|
| 107 | + <div style="display: flex; flex-direction: row; width: 100%;"> |
| 108 | + <!-- Code Container --> |
| 109 | + <div id="code-container"> |
| 110 | + <div style="overflow: hidden; height: 50px; flex-shrink: 0; display: flex; flex-direction: row; align-items: center; background: #fff; border-bottom: 1px solid #CCC;"> |
| 111 | + <span style="user-select: none; margin:0; float:left; font-size: 20px; padding: 10px; flex-grow:1;">Code</span> |
| 112 | + </div> |
| 113 | + <div id="code" style="width: 100%; height: 100%;"></div> |
| 114 | + </div> |
| 115 | + |
| 116 | + <!-- Resizer --> |
| 117 | + <div class="resizer"></div> |
| 118 | +
|
| 119 | + <!-- Output Container --> |
| 120 | + <div id="output-container"> |
| 121 | + <div style="overflow: hidden; height: 50px; flex-shrink: 0; display: flex; flex-direction: row; align-items: center; background: #fff; border-bottom: 1px solid #CCC;"> |
| 122 | + <span style="user-select: none; margin:0; float:left; font-size: 20px; padding: 10px; flex-grow: 1;">Preview</span> |
| 123 | + <button id="run"><span></span>Run</button> |
| 124 | + </div> |
| 125 | + <div id="output" style="width: 100%; height: 100%;"></div> |
| 126 | + </div> |
| 127 | + </div> |
| 128 | + </div> |
| 129 | + <iframe id="initial-code" style="display:none;">{{CODE}}</iframe> |
| 130 | + <script src="/playground/assets/js/app.js"></script> |
| 131 | +</body> |
| 132 | +
|
| 133 | +</html>` |
| 134 | + |
| 135 | +const generatePlayground = () => { |
| 136 | + // Generate sidebar HTML once for all examples |
| 137 | + const sidebarHtml = generateSidebarHtml(examples); |
| 138 | + |
| 139 | + let totalExamples = 0; |
| 140 | + |
| 141 | + examples.forEach(section => { |
| 142 | + section.children.forEach(example => { |
| 143 | + // Read source file from src/ directory |
| 144 | + const sourcePath = path.join('src', example.source); |
| 145 | + const sourceContent = fs.readFileSync(sourcePath, 'utf8'); |
| 146 | + |
| 147 | + // Copy playgroundHtml to avoid tainting the original |
| 148 | + let htmlTemplate = playgroundHtml.slice(); |
| 149 | + |
| 150 | + htmlTemplate = htmlTemplate.replace('{{SIDEBAR}}', sidebarHtml); |
| 151 | + const pageTitle = example.slug === '' ? 'Puter.js Playground' : `${example.title} | Puter.js Playground`; |
| 152 | + htmlTemplate = htmlTemplate.replaceAll('{{TITLE}}', pageTitle); |
| 153 | + const pageDescription = example.description || 'Try Puter.js instantly with interactive examples in your browser. Run, edit, and experiment with code - no installation or setup required.'; |
| 154 | + htmlTemplate = htmlTemplate.replaceAll('{{DESCRIPTION}}', pageDescription); |
| 155 | + const canonicalUrl = `https://docs.puter.com/playground/${example.slug ? example.slug + '/' : ''}`; |
| 156 | + htmlTemplate = htmlTemplate.replaceAll('{{CANONICAL}}', canonicalUrl); |
| 157 | + const finalHtml = htmlTemplate.replace('{{CODE}}', sourceContent); |
| 158 | + |
| 159 | + // Create output directory |
| 160 | + const outputDir = path.join('dist', 'playground', example.slug); |
| 161 | + fs.mkdirSync(outputDir, { recursive: true }); |
| 162 | + |
| 163 | + // Write the file |
| 164 | + const outputPath = path.join(outputDir, 'index.html'); |
| 165 | + fs.writeFileSync(outputPath, finalHtml, 'utf8'); |
| 166 | + |
| 167 | + totalExamples++; |
| 168 | + }); |
| 169 | + }); |
| 170 | + console.log(`Generated ${totalExamples} playground examples.`); |
| 171 | +} |
| 172 | + |
| 173 | +module.exports = { generatePlayground }; |
0 commit comments