Skip to content

Commit

Permalink
feat(specs): add playground
Browse files Browse the repository at this point in the history
goal of this is to replace storybook at term, once it's all working as we expect.

What's currently done:

An example done for Breadcrumb using Sandpack for all flavours, using npm/codesandbox to get the package contents

What still should be done

- fix ssr styling (somehow dark first)
- local package (and built package for site)
- some styling:
  - Maybe tabs for the examples
  - actually differentiate between "focused widget" and the regular app
  - "full screen mode"
- see if we really need only one example per widget, otherwise design for multiple examples
  • Loading branch information
Haroenv committed Dec 26, 2023
1 parent fd5dc5b commit 39a7bcf
Show file tree
Hide file tree
Showing 7 changed files with 802 additions and 26 deletions.
11 changes: 11 additions & 0 deletions specs/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import react from '@astrojs/react';
import { defineConfig } from 'astro/config';

export default defineConfig({
site: 'https://instantsearchjs.netlify.app/',
base: '/specs',
outDir: '../website/specs',
integrations: [react()],
vite: {
ssr: {
noExternal: [
'@codesandbox/sandpack-react',
'@codesandbox/sandpack-themes',
'@codesandbox/sandpack-client',
],
},
},
});
6 changes: 5 additions & 1 deletion specs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
"devDependencies": {
"@types/node": "18.11.13",
"astro": "4.0.4",
"@astrojs/react": "3.0.8",
"instantsearch.css": "8.1.0",
"sass": "1.56.2"
"sass": "1.56.2",
"@codesandbox/sandpack-react": "2.10.0",
"@codesandbox/sandpack-themes": "2.0.21",
"dedent": "1.5.1"
}
}
199 changes: 199 additions & 0 deletions specs/src/components/Sandbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/* eslint-disable react/react-in-jsx-scope */
import { Sandpack } from '@codesandbox/sandpack-react';
import { githubLight } from '@codesandbox/sandpack-themes';
import dedent from 'dedent';

const settings = {
js: {
html: /* HTML */ `
<style>
body {
font-family: sans-serif;
}
</style>
<div id="custom"></div>
<div id="searchbox"></div>
<div id="hits"></div>
`,
preamble: /* JS */ `
import 'instantsearch.css/themes/satellite-min.css';
import algoliasearch from 'algoliasearch/lite';
import instantsearch from 'instantsearch.js';
import { history } from 'instantsearch.js/es/lib/routers';
import { searchBox, hits } from 'instantsearch.js/es/widgets';
import { createWidgets } from './widget.ts';
const search = instantsearch({
indexName: 'instant_search',
searchClient: algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76'),
future: {
preserveSharedStateOnUnmount: true,
},
routing: {
router: history({
cleanUrlOnDispose: false,
})
}
});
search.addWidgets([
...createWidgets(document.querySelector('#custom')),
searchBox({
container: '#searchbox',
}),
hits({
container: '#hits',
templates: {
item: (hit, { components }) => components.Highlight({ attribute: 'name', hit }),
},
}),
]);
search.start();
`,
dependencies: {
// TODO: use current version somehow, both locally and in the built website
'instantsearch.js': 'latest',
'instantsearch.css': 'latest',
algoliasearch: 'latest',
},
filename: '/widget.ts',
},
react: {
html: /* HTML */ `
<style>
body {
font-family: sans-serif;
}
</style>
<main id="root"></main>
`,
preamble: /* TSX */ `
import 'instantsearch.css/themes/satellite-min.css';
import React from "react";
import { createRoot } from "react-dom/client";
import algoliasearch from "algoliasearch/lite";
import { history } from "instantsearch.js/es/lib/routers";
import { InstantSearch, SearchBox, Hits, Highlight } from "react-instantsearch";
import { widgets } from "./widget.tsx";
createRoot(document.getElementById('root')).render(
<InstantSearch
indexName="instant_search"
searchClient={algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76')}
future={{
preserveSharedStateOnUnmount: true,
}}
routing={{
router: history({
cleanUrlOnDispose: false,
})
}}
>
{widgets}
<SearchBox />
<Hits hitComponent={Hit}/>
</InstantSearch>
);
function Hit({ hit }) {
return <Highlight hit={hit} attribute="name" />;
}
`,
dependencies: {
react: 'latest',
'react-dom': 'latest',
algoliasearch: 'latest',
'instantsearch.css': 'latest',
'react-instantsearch': 'latest',
},
filename: '/widget.tsx',
},
vue: {
html: /* HTML */ `
<style>
body {
font-family: sans-serif;
}
</style>
<main id="app"></main>
`,
preamble: `
import "instantsearch.css/themes/satellite-min.css";
import Vue from "vue";
import algoliasearch from "algoliasearch/lite";
import { history } from "instantsearch.js/es/lib/routers";
import { AisInstantSearch, AisHits, AisSearchBox } from "vue-instantsearch/vue2/es";
import Widget from "./Widget.vue";
Vue.config.productionTip = false;
new Vue({
render: (h) =>
h(
AisInstantSearch,
{
props: {
searchClient: algoliasearch(
"latency",
"6be0576ff61c053d5f9a3225e2a90f76"
),
indexName: "instant_search",
future: {
preserveSharedStateOnUnmount: true,
},
routing: {
router: history({
cleanUrlOnDispose: false,
})
}
},
},
[h(Widget), h(AisSearchBox), h(AisHits)]
),
}).$mount("#app");
`,
dependencies: {
vue: '2',
algoliasearch: 'latest',
'instantsearch.css': 'latest',
'vue-instantsearch': 'latest',
},
filename: '/Widget.vue',
},
};

export default function Sandbox({
code,
flavor,
}: {
code: string;
flavor: 'react' | 'js' | 'vue';
}) {
const { preamble, html, filename, dependencies } = settings[flavor];
return (
<Sandpack
files={{
'/index.html': {
hidden: true,
code: dedent(html),
},
'/index.js': {
code: dedent(preamble),
},
[filename]: {
code,
},
}}
customSetup={{
dependencies,
entry: '/index.js',
}}
options={{
activeFile: filename,
showNavigator: true,
}}
theme={githubLight}
/>
);
}
22 changes: 21 additions & 1 deletion specs/src/components/WidgetContent.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import { Code } from 'astro/components';
import type { WidgetFrontmatter } from '../types';
import ThemeSelector from './ThemeSelector.astro';
import Sandbox from './Sandbox.jsx';
import { getSandpackCssText } from "@codesandbox/sandpack-react";
type Props = {
frontmatter: WidgetFrontmatter;
Expand All @@ -23,7 +26,8 @@ const title = frontmatter.title;
{
frontmatter.info && (
<div class="info">
<p>{frontmatter.info}</p>
{' '}
<p>{frontmatter.info}</p>{' '}
</div>
)
}
Expand Down Expand Up @@ -110,6 +114,22 @@ const title = frontmatter.title;
)
}

{frontmatter.examples ? (
<>
<h3 id="example">Usage</h3>
<!-- TODO: theme is implied dark? -->
<style is:inline set:html={getSandpackCssText()}></style>
{frontmatter.examples.map(({ code, flavor, library }) => (
<div class="example">
<h4>{library}</h4>
<div class="code-output">
<Sandbox code={code} flavor={flavor} client:load />
</div>
</div>
))}
</>
) : null}

<h3 id="css-classes">CSS classes</h3>
{
frontmatter.classes ? (
Expand Down
1 change: 1 addition & 0 deletions specs/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/// <reference path="../.astro/types.d.ts" />
// / <reference types="astro/client" />
53 changes: 53 additions & 0 deletions specs/src/pages/widgets/breadcrumb.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,57 @@ translations:
- name: separatorText
default: '" > "'
description: The text for the breadcrumb’s separator.
examples:
- flavor: js
library: instantsearch.js
code: |
import { breadcrumb } from 'instantsearch.js/es/widgets';
export const createWidgets = (container) => [
breadcrumb({
container,
attributes: [
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
'hierarchicalCategories.lvl2',
],
}),
];
- flavor: react
library: react-instantsearch
code: |
import React from 'react';
import { Breadcrumb } from 'react-instantsearch';
export const widgets = (
<Breadcrumb
attributes={[
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
'hierarchicalCategories.lvl2',
]}
/>
);
- flavor: vue
library: vue-instantsearch
code: |
<template>
<ais-breadcrumb
:attributes="[
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
'hierarchicalCategories.lvl2',
]"
/>
</template>
<script>
import { AisBreadcrumb } from 'vue-instantsearch';
export default {
components: {
AisBreadcrumb,
},
};
</script>
---
Loading

0 comments on commit 39a7bcf

Please sign in to comment.