diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..8af8493 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,16 @@ +# Flows examples + +This directory contains examples of flows that can be used as a starting point for your own Flows implementation. + +## Examples + +- [React Next.js](./react-nextjs) - A simple example of how to use Flows with React and Next.js. +- [JavaScript](./javascript) - A simple example of how to use Flows with vanilla JavaScript. + +## Reporting Issues + +We actively encourage our community to raise issues and provide feedback. If you find an issue, please let us know by raising an issue in the repository. + +An issue can be raised by clicking the 'Issues' tab at the top of the repository, followed by the Green 'New issue' button. + +When submitting an issue, please thoroughly and concisely describe the problem you are experiencing so that we may easily understand and resolve the issue in a timely manner. diff --git a/examples/vanilla-js/.gitignore b/examples/javascript/.gitignore similarity index 100% rename from examples/vanilla-js/.gitignore rename to examples/javascript/.gitignore diff --git a/examples/javascript/arrow.svg b/examples/javascript/arrow.svg new file mode 100644 index 0000000..91635fb --- /dev/null +++ b/examples/javascript/arrow.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/examples/vanilla-js/favicon.ico b/examples/javascript/favicon.ico similarity index 100% rename from examples/vanilla-js/favicon.ico rename to examples/javascript/favicon.ico diff --git a/examples/javascript/index.html b/examples/javascript/index.html new file mode 100644 index 0000000..1edb9a0 --- /dev/null +++ b/examples/javascript/index.html @@ -0,0 +1,233 @@ + + + + + + + Flows - JavaScript example + + + + + + + + + +
+
+
+
+

Flows JavaScript example

+

+ Get started at  + + flows.sh + +

+
+ +
+
+
+
+ + +
+
+
+ + +
+
+

Your files

+
+
+ File 1 +
+
+ File 2 +
+
+ File 3 +
+
+ File 4 +
+
+
+
+
+ +
+ diff --git a/examples/javascript/logo.svg b/examples/javascript/logo.svg new file mode 100644 index 0000000..6f66e11 --- /dev/null +++ b/examples/javascript/logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/vanilla-js/package.json b/examples/javascript/package.json similarity index 100% rename from examples/vanilla-js/package.json rename to examples/javascript/package.json diff --git a/examples/javascript/styles.css b/examples/javascript/styles.css new file mode 100644 index 0000000..b323f2a --- /dev/null +++ b/examples/javascript/styles.css @@ -0,0 +1,293 @@ +* { + box-sizing: border-box; + padding: 0; + margin: 0; + + --bg-default: #fff; + --bg-muted: #fafafa; + --bg-hover: #f5f5f5; + --bg-primary: #ec6441; + --bg-primary-hover: #d44121; + + --fg-default: #181818; + --fg-muted: #525252; + --fg-on-primary: #fff; + + --border-default: #e2e2e2; + + --shadow-l1: 0px 2px 2px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.08); + --shadow-l2: 4px 8px 10.1px -2.5px rgba(10, 10, 10, 0.08), + 1.7px 3.3px 4.2px -1.7px rgba(10, 10, 10, 0.09), 0.7px 1.4px 1.8px -0.8px rgba(10, 10, 10, 0.1), + 0px 0.5px 1.5px 0px rgba(10, 10, 10, 0.2); +} + +html, +body { + font-family: + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + Oxygen, + Ubuntu, + Cantarell, + "Open Sans", + "Helvetica Neue", + sans-serif; + max-width: 100vw; + height: 100%; + overflow-x: hidden; + font-size: 10px; + background-color: var(--bg-muted); + color: var(--fg-default); +} + +main { + display: flex; + flex-direction: column; + gap: 16px; + justify-content: space-between; + + height: 100%; + + background-image: radial-gradient(#e2e2e2 1px, transparent 0); + background-size: 16px 16px; +} + +.callout p { + color: var(--fg-muted); +} + +h1 { + font-size: 2rem; + line-height: 2.6rem; +} + +h2 { + font-size: 1.6rem; + line-height: 2.2rem; +} + +p { + font-size: 1.4rem; + line-height: 2rem; +} + +.header { + padding: 4rem; + background-color: var(--bg-default); + border-bottom: 1px solid var(--border-default); +} + +.header-inner-wrap { + display: flex; + justify-content: space-between; + align-items: center; + + max-width: 96rem; + margin: 0 auto; +} + +.link { + color: var(--fg-default); + text-decoration: none; + font-weight: 600; +} + +.link:hover { + text-decoration: underline; +} + +button { + padding: 1rem 2rem; + border: none; + border-radius: 8px; + background-color: var(--bg-primary); + color: var(--fg-on-primary); + font-size: 1.4rem; + font-weight: 600; + cursor: pointer; +} + +button:hover { + background-color: var(--bg-primary-hover); +} + +.btn-secondary { + background-color: var(--bg-muted); + color: var(--fg-default); + border: 1px solid var(--border-default); +} + +.btn-secondary:hover { + background-color: var(--bg-hover); +} + +.main-wrapper { + display: flex; + flex-direction: column; + max-width: 96rem; + max-height: 48rem; + width: 100%; + margin: 0 auto; + padding: 2.4rem; +} + +.footer { + padding: 4rem; + background-color: var(--bg-default); + border-top: 1px solid var(--border-default); +} + +.footer-inner-wrap { + display: flex; + gap: 1.6rem; + + max-width: 96rem; + margin: 0 auto; +} + +.footer-link { + display: flex; + flex-direction: column; + gap: 0.8rem; + padding: 1.6rem; + width: 100%; + + border: 1px solid var(--border-default); + border-radius: 8px; + cursor: pointer; + transition: all 120ms ease-in-out; + + text-decoration: none; + color: var(--fg-default); +} + +.footer-link:hover { + text-decoration: none; + + box-shadow: var(--shadow-l2); +} + +.footer-link-text { + color: var(--fg-muted); +} + +.footer-heading { + display: flex; + align-items: center; +} + +.footer-heading::after { + content: ""; + background-image: url("/arrow.svg"); + width: 1.6rem; + height: 1.6rem; + display: inline-flex; + margin-left: 0.4rem; + transition: all 120ms ease-in-out; +} + +.footer-link:hover .footer-heading::after { + margin-left: 0.8rem; +} + +.app-wrapper { + display: flex; + flex-direction: column; + + background-color: var(--bg-default); + border: 1px solid var(--border-default); + border-radius: 8px; + box-shadow: var(--shadow-l2); +} + +.app-header { + display: flex; + justify-content: space-between; + align-items: center; + + padding: 1.6rem; + border-bottom: 1px solid var(--border-default); +} + +.app-logo { + font-size: 1.6rem; + font-weight: 600; +} + +.app-content { + padding: 1.6rem; +} + +.app-files { + display: flex; + flex-direction: column; + + border: 1px solid var(--border-default); + border-radius: 8px; + overflow: hidden; +} + +.app-file-item { + display: flex; + justify-content: space-between; + align-items: center; + + padding: 1.6rem; + border-bottom: 1px solid var(--border-default); + + font-size: 1.4rem; + font-weight: 600; + cursor: pointer; +} + +.app-file-item:last-child { + border-bottom: none; +} + +.app-file-item:hover { + background-color: var(--bg-hover); +} + +.app-list-title { + margin-bottom: 0.8rem; +} + +.flows-launch-wrapper { + display: flex; + justify-content: center; + margin-bottom: 2.4rem; + gap: 1.6rem; + + padding: 1.6rem; + border: 1px solid var(--border-default); + border-radius: 8px; + background-color: var(--bg-muted); +} + +@media (max-width: 768px) { + .header-inner-wrap { + flex-direction: column-reverse; + gap: 1.6rem; + } + + .footer-inner-wrap { + flex-direction: column; + gap: 1.6rem; + } + + .logo { + display: none; + } + .header { + padding: 2.4rem; + } + .footer { + padding: 2.4rem; + } + .callout { + width: 100%; + } +} diff --git a/examples/react-nextjs/app/globals.css b/examples/react-nextjs/app/globals.css index fc42ebb..3e0e266 100644 --- a/examples/react-nextjs/app/globals.css +++ b/examples/react-nextjs/app/globals.css @@ -2,19 +2,280 @@ box-sizing: border-box; padding: 0; margin: 0; + + --bg-default: #fff; + --bg-muted: #fafafa; + --bg-hover: #f5f5f5; + --bg-primary: #ec6441; + --bg-primary-hover: #d44121; + + --fg-default: #181818; + --fg-muted: #525252; + --fg-on-primary: #fff; + + --border-default: #e2e2e2; + + --shadow-l1: 0px 2px 2px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.08); + --shadow-l2: 4px 8px 10.1px -2.5px rgba(10, 10, 10, 0.08), + 1.7px 3.3px 4.2px -1.7px rgba(10, 10, 10, 0.09), 0.7px 1.4px 1.8px -0.8px rgba(10, 10, 10, 0.1), + 0px 0.5px 1.5px 0px rgba(10, 10, 10, 0.2); } html, body { max-width: 100vw; + height: 100%; overflow-x: hidden; + font-size: 10px; + background-color: var(--bg-muted); + color: var(--fg-default); } -header, main { - padding: 16px 16px; + display: flex; + flex-direction: column; + gap: 16px; + justify-content: space-between; + + height: 100%; + + background-image: radial-gradient(#e2e2e2 1px, transparent 0); + background-size: 16px 16px; +} + +.callout p { + color: var(--fg-muted); +} + +h1 { + font-size: 2rem; + line-height: 2.6rem; +} + +h2 { + font-size: 1.6rem; + line-height: 2.2rem; +} + +p { + font-size: 1.4rem; + line-height: 2rem; +} + +.header { + padding: 4rem; + background-color: var(--bg-default); + border-bottom: 1px solid var(--border-default); +} + +.header-inner-wrap { + display: flex; + justify-content: space-between; + align-items: center; + + max-width: 96rem; + margin: 0 auto; +} + +.link { + color: var(--fg-default); + text-decoration: none; + font-weight: 600; } -header ul { - padding-left: 16px; +.link:hover { + text-decoration: underline; +} + +button { + padding: 1rem 2rem; + border: none; + border-radius: 8px; + background-color: var(--bg-primary); + color: var(--fg-on-primary); + font-size: 1.4rem; + font-weight: 600; + cursor: pointer; +} + +button:hover { + background-color: var(--bg-primary-hover); +} + +.btn-secondary { + background-color: var(--bg-muted); + color: var(--fg-default); + border: 1px solid var(--border-default); +} + +.btn-secondary:hover { + background-color: var(--bg-hover); +} + +.main-wrapper { + display: flex; + flex-direction: column; + max-width: 96rem; + max-height: 48rem; + width: 100%; + margin: 0 auto; + padding: 2.4rem; +} + +.footer { + padding: 4rem; + background-color: var(--bg-default); + border-top: 1px solid var(--border-default); +} + +.footer-inner-wrap { + display: flex; + gap: 1.6rem; + + max-width: 96rem; + margin: 0 auto; +} + +.footer-link { + display: flex; + flex-direction: column; + gap: 0.8rem; + padding: 1.6rem; + width: 100%; + + border: 1px solid var(--border-default); + border-radius: 8px; + cursor: pointer; + transition: all 120ms ease-in-out; + + text-decoration: none; + color: var(--fg-default); +} + +.footer-link:hover { + text-decoration: none; + + box-shadow: var(--shadow-l2); +} + +.footer-link-text { + color: var(--fg-muted); +} + +.footer-heading { + display: flex; + align-items: center; +} + +.footer-heading::after { + content: ""; + background-image: url("/arrow.svg"); + width: 1.6rem; + height: 1.6rem; + display: inline-flex; + margin-left: 0.4rem; + transition: all 120ms ease-in-out; +} + +.footer-link:hover .footer-heading::after { + margin-left: 0.8rem; +} + +.app-wrapper { + display: flex; + flex-direction: column; + + background-color: var(--bg-default); + border: 1px solid var(--border-default); + border-radius: 8px; + box-shadow: var(--shadow-l2); +} + +.app-header { + display: flex; + justify-content: space-between; + align-items: center; + + padding: 1.6rem; + border-bottom: 1px solid var(--border-default); +} + +.app-logo { + font-size: 1.6rem; + font-weight: 600; +} + +.app-content { + padding: 1.6rem; +} + +.app-files { + display: flex; + flex-direction: column; + + border: 1px solid var(--border-default); + border-radius: 8px; + overflow: hidden; +} + +.app-file-item { + display: flex; + justify-content: space-between; + align-items: center; + + padding: 1.6rem; + border-bottom: 1px solid var(--border-default); + + font-size: 1.4rem; + font-weight: 600; + cursor: pointer; +} + +.app-file-item:last-child { + border-bottom: none; +} + +.app-file-item:hover { + background-color: var(--bg-hover); +} + +.app-list-title { + margin-bottom: 0.8rem; +} + +.flows-launch-wrapper { + display: flex; + justify-content: center; + margin-bottom: 2.4rem; + gap: 1.6rem; + + padding: 1.6rem; + border: 1px solid var(--border-default); + border-radius: 8px; + background-color: var(--bg-muted); +} + +@media (max-width: 768px) { + .header-inner-wrap { + flex-direction: column-reverse; + gap: 1.6rem; + } + + .footer-inner-wrap { + flex-direction: column; + gap: 1.6rem; + } + + .logo { + display: none; + } + .header { + padding: 2.4rem; + } + .footer { + padding: 2.4rem; + } + .callout { + width: 100%; + } } diff --git a/examples/react-nextjs/app/page.tsx b/examples/react-nextjs/app/page.tsx index 7b5ea4b..9892523 100644 --- a/examples/react-nextjs/app/page.tsx +++ b/examples/react-nextjs/app/page.tsx @@ -1,9 +1,99 @@ export default function HomePage() { return ( - <> -

Flows - React Next.js example

- - - +
+
+
+
+

Flows React Next.js example

+

+ Get started at  + + flows.sh + +

+
+ + FlowsJS + +
+
+
+
+ + +
+
+
+

DropCrate

+ +
+
+

Your files

+
+
+ File 1 +
+
+ File 2 +
+
+ File 3 +
+
+ File 4 +
+
+
+
+
+
+
+ +

Docs

+

Learn how to use Flows to build user onboarding.

+
+ +

Sign up

+

Create a Flows account and start creating flows.

+
+ +

See other demos

+

Visit our GitHub repo to see other examples.

+
+ +

See source code

+

+ Visit our GitHub repo to what makes this example tick. +

+
+
+
+
); } diff --git a/examples/react-nextjs/components/flows.tsx b/examples/react-nextjs/components/flows.tsx index bcae177..f6c0839 100644 --- a/examples/react-nextjs/components/flows.tsx +++ b/examples/react-nextjs/components/flows.tsx @@ -11,15 +11,112 @@ export const Flows = () => { { id: "local-flow", clickElement: "#start-local", + frequency: "every-time", steps: [ { - targetElement: "#start-local", - title: "Welcome to FlowsJS!", - body: "This is a demo of FlowsJS. Click the button below to continue.", + title: "Welcome to Flows!", + body: "This is a demo of a local flow loaded from the codebase. Flows offer cloud flows as well, which can be updated without needing code changes.", }, { - title: "This is a modal", - body: "This is a modal. It is an useful way to show larger amounts of information with detailed descriptions. For smaller amounts of information, you can use a tooltip. Click the button below to continue.", + title: "This is a tooltip", + body: "It can have an overlay...", + targetElement: "#file1", + overlay: true, + }, + { + title: "...or not", + body: "You can customize the tooltip to your liking.", + targetElement: "#file1", + }, + { + title: "You can also wait for a click", + body: "Just like this! Click the button to continue.", + targetElement: "#upload", + overlay: true, + wait: { + clickElement: "#upload", + }, + hideNext: true, + }, + { + title: "Or you can branch out with forks", + body: "Click on one of the files to continue.", + targetElement: ".app-files", + overlay: true, + wait: [ + { + clickElement: "#file1", + targetBranch: 0, + }, + { + clickElement: "#file2", + targetBranch: 1, + }, + { + clickElement: "#file3", + targetBranch: 2, + }, + { + clickElement: "#file4", + targetBranch: 3, + }, + ], + hideNext: true, + }, + [ + [ + { + title: "You clicked on file 1", + body: "With forks, you can create multiple branches to tailor the onboarding to user actions.", + targetElement: "#file1", + overlay: true, + }, + ], + [ + { + title: "You clicked on file 2", + body: "With forks, you can create multiple branches to tailor the onboarding to user actions.", + targetElement: "#file2", + overlay: true, + }, + ], + [ + { + title: "You clicked on file 3", + body: "With forks, you can create multiple branches to tailor the onboarding to user actions.", + targetElement: "#file3", + overlay: true, + }, + ], + [ + { + title: "You clicked on file 4", + body: "With forks, you can create multiple branches to tailor the onboarding to user actions.", + targetElement: "#file4", + overlay: true, + }, + ], + ], + { + title: "That was the basics of Flows!", + body: "You can create complex onboarding flows with Flows or a simple tour. If you liked what you saw, sign up and start creating your own flows.", + hideNext: true, + hidePrev: true, + footerActions: { + center: [ + { + label: "Learn more", + external: true, + href: "https://flows.sh/docs", + variant: "secondary", + }, + { + label: "Sign up", + external: true, + href: "https://app.flows.sh/signup", + }, + ], + }, }, ], }, diff --git a/examples/react-nextjs/public/arrow.svg b/examples/react-nextjs/public/arrow.svg new file mode 100644 index 0000000..91635fb --- /dev/null +++ b/examples/react-nextjs/public/arrow.svg @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/examples/react-nextjs/public/logo.svg b/examples/react-nextjs/public/logo.svg new file mode 100644 index 0000000..6f66e11 --- /dev/null +++ b/examples/react-nextjs/public/logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/vanilla-js/index.html b/examples/vanilla-js/index.html deleted file mode 100644 index d0bd7e3..0000000 --- a/examples/vanilla-js/index.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - Flows - Vanilla JS example - - - - - - - - -
-

Flows - Vanilla JS example

- - - - diff --git a/examples/vanilla-js/index.js b/examples/vanilla-js/index.js deleted file mode 100644 index 1c1e634..0000000 --- a/examples/vanilla-js/index.js +++ /dev/null @@ -1,20 +0,0 @@ -window.FlowsJS?.init({ - projectId: "e7d8eb63-7670-4da1-b0e0-d2d3331d108b", - flows: [ - { - id: "local-flow", - clickElement: "#start-local", - steps: [ - { - targetElement: "#start-local", - title: "Welcome to FlowsJS!", - body: "This is a demo of FlowsJS. Click the button below to continue.", - }, - { - title: "This is a modal", - body: "This is a modal. It is an useful way to show larger amounts of information with detailed descriptions. For smaller amounts of information, you can use a tooltip. Click the button below to continue.", - }, - ], - }, - ], -});