diff --git a/.changeset/fifty-rabbits-give.md b/.changeset/fifty-rabbits-give.md new file mode 100644 index 0000000..1576982 --- /dev/null +++ b/.changeset/fifty-rabbits-give.md @@ -0,0 +1,6 @@ +--- +"docs": patch +"@stepperize/react": patch +--- + +docs, react: add examples and index to current step diff --git a/.changeset/young-buses-look.md b/.changeset/young-buses-look.md new file mode 100644 index 0000000..04504ae --- /dev/null +++ b/.changeset/young-buses-look.md @@ -0,0 +1,7 @@ +--- +"docs": minor +"react": minor +--- + +docs: improve docs with fumadocs and add examples with Stackblitz +react: add index to current value and new match method diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index e69de29..0000000 diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore new file mode 100644 index 0000000..51c0e6b --- /dev/null +++ b/apps/docs/.gitignore @@ -0,0 +1,28 @@ +# deps +/node_modules + +# generated content +.map.ts +.contentlayer +.content-collections + +# test & build +/coverage +/.next/ +/out/ +/build +*.tsbuildinfo + +# misc +.DS_Store +*.pem +/.pnp +.pnp.js +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# others +.env*.local +.vercel +next-env.d.ts \ No newline at end of file diff --git a/apps/docs/.source/index.d.ts b/apps/docs/.source/index.d.ts new file mode 100644 index 0000000..3eca4d1 --- /dev/null +++ b/apps/docs/.source/index.d.ts @@ -0,0 +1,3 @@ +import type { GetOutput } from "fumadocs-mdx/config" +export declare const docs: GetOutput +export declare const meta: GetOutput \ No newline at end of file diff --git a/apps/docs/.source/index.js b/apps/docs/.source/index.js new file mode 100644 index 0000000..7ee75cc --- /dev/null +++ b/apps/docs/.source/index.js @@ -0,0 +1,19 @@ +import { toRuntime } from "fumadocs-mdx" +import * as file_0 from "../content/docs/react/index.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_1 from "../content/docs/react/installation.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_2 from "../content/docs/react/api-references/define.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_3 from "../content/docs/react/api-references/hook.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_4 from "../content/docs/react/api-references/scoped.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_5 from "../content/docs/react/examples/basic.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_6 from "../content/docs/react/examples/conform-react.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_7 from "../content/docs/react/examples/dialog.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_8 from "../content/docs/react/examples/multi-scoped.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_9 from "../content/docs/react/examples/query-params.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_10 from "../content/docs/react/examples/react-hook-form.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_11 from "../content/docs/react/examples/scoped.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_12 from "../content/docs/react/examples/shareable-data.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_13 from "../content/docs/react/migration/migrating-to-v2.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_14 from "../content/docs/react/migration/migrating-to-v3.mdx?collection=docs&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +import * as file_15 from "../content/docs/react/meta.json?collection=meta&hash=bc7c7620ff6e63a97b7e6e3e162afe44094dd17f054ad7cc7a1bf479cef93850" +export const docs = [toRuntime("doc", file_0, {"path":"react/index.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/index.mdx"}),toRuntime("doc", file_1, {"path":"react/installation.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/installation.mdx"}),toRuntime("doc", file_2, {"path":"react/api-references/define.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/api-references/define.mdx"}),toRuntime("doc", file_3, {"path":"react/api-references/hook.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/api-references/hook.mdx"}),toRuntime("doc", file_4, {"path":"react/api-references/scoped.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/api-references/scoped.mdx"}),toRuntime("doc", file_5, {"path":"react/examples/basic.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/basic.mdx"}),toRuntime("doc", file_6, {"path":"react/examples/conform-react.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/conform-react.mdx"}),toRuntime("doc", file_7, {"path":"react/examples/dialog.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/dialog.mdx"}),toRuntime("doc", file_8, {"path":"react/examples/multi-scoped.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/multi-scoped.mdx"}),toRuntime("doc", file_9, {"path":"react/examples/query-params.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/query-params.mdx"}),toRuntime("doc", file_10, {"path":"react/examples/react-hook-form.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/react-hook-form.mdx"}),toRuntime("doc", file_11, {"path":"react/examples/scoped.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/scoped.mdx"}),toRuntime("doc", file_12, {"path":"react/examples/shareable-data.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/examples/shareable-data.mdx"}),toRuntime("doc", file_13, {"path":"react/migration/migrating-to-v2.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/migration/migrating-to-v2.mdx"}),toRuntime("doc", file_14, {"path":"react/migration/migrating-to-v3.mdx","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/migration/migrating-to-v3.mdx"})] +export const meta = [toRuntime("meta", file_15, {"path":"react/meta.json","absolutePath":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/meta.json"})] \ No newline at end of file diff --git a/apps/docs/.source/manifest.json b/apps/docs/.source/manifest.json new file mode 100644 index 0000000..92ce136 --- /dev/null +++ b/apps/docs/.source/manifest.json @@ -0,0 +1 @@ +{"files":[{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/index.mdx","data":{"lastModified":1726164504000,"frontmatter":{"title":"Introduction","description":"Introduction to @stepperize/react library","icon":"Album"},"toc":[{"title":"Thinking in Steps","url":"#thinking-in-steps","depth":2},{"title":"Common Use Cases for Steppers","url":"#common-use-cases-for-steppers","depth":3},{"title":"Thinking in Flows","url":"#thinking-in-flows","depth":2},{"title":"Using Stepperize for Flow Management","url":"#using-stepperize-for-flow-management","depth":3},{"title":"Stepperize FAQ","url":"#stepperize-faq","depth":2}],"structuredData":{"contents":[{"heading":"","content":"Stepperize is a library that allows to create a Stepper component in a simple and fast way."},{"heading":"","content":"The aim is to facilitate the creation of Steppers in web or mobile apps (React Native), allowing developers to focus on the business logic and not on the implementation of a Stepper."},{"heading":"thinking-in-steps","content":"When we talk about a Stepper, we usually think about a sequence of steps that the user must follow to complete a task.\nThis UI pattern guides users through a multi-step process, breaking down complex workflows into manageable chunks.\nSteppers typically display progress, provide clear navigation between steps, and often include visual cues like numbers or icons to represent each stage."},{"heading":"common-use-cases-for-steppers","content":"Steppers are versatile components that can be applied to various scenarios:"},{"heading":"common-use-cases-for-steppers","content":"User Onboarding: Guide new users through account setup, feature introduction, or initial configuration."},{"heading":"common-use-cases-for-steppers","content":"Multi-page Forms: Break long forms into logical sections, reducing cognitive load and improving completion rates."},{"heading":"common-use-cases-for-steppers","content":"Checkout Processes: Streamline e-commerce transactions by clearly separating steps like shipping, billing, and confirmation."},{"heading":"common-use-cases-for-steppers","content":"Product Creation Wizards: Assist users in creating complex items or configurations step-by-step."},{"heading":"common-use-cases-for-steppers","content":"Tutorial Walkthroughs: Introduce new features or guide users through complex processes within an application."},{"heading":"common-use-cases-for-steppers","content":"Survey or Questionnaire Flow: Present questions in a structured, sequential manner."},{"heading":"common-use-cases-for-steppers","content":"Booking Systems: Guide users through selecting dates, options, and completing reservations."},{"heading":"common-use-cases-for-steppers","content":"By implementing Steppers in these scenarios, you can enhance user experience, reduce errors, and make complex processes more manageable."},{"heading":"thinking-in-flows","content":"Stepperize isn't just limited to linear step-by-step processes. It can be extended to manage complex flows and conditional rendering based on various factors. This approach allows you to create dynamic, branching user experiences that adapt to user input or specific conditions."},{"heading":"using-stepperize-for-flow-management","content":"Conditional Rendering: Render different components or entire flows based on the current step or user choices."},{"heading":"using-stepperize-for-flow-management","content":"Branching Paths: Create decision trees where the next step depends on previous inputs or selections."},{"heading":"using-stepperize-for-flow-management","content":"Dynamic Forms: Adjust form fields or sections based on user responses in earlier steps."},{"heading":"using-stepperize-for-flow-management","content":"Personalized Experiences: Tailor the flow to user preferences, roles, or account types."},{"heading":"using-stepperize-for-flow-management","content":"State-Dependent UI: Change the interface based on the current state of the flow, such as showing different sidebars or navigation options."},{"heading":"using-stepperize-for-flow-management","content":"Multi-Path Processes: Handle complex workflows where users might need to complete different sets of steps based on their scenario."},{"heading":"using-stepperize-for-flow-management","content":"By leveraging Stepperize's flexibility, you can build sophisticated user interfaces that go beyond simple linear progressions, creating more responsive and user-centric applications."},{"heading":"stepperize-faq","content":"The Stepperize FAQ is a collection of useful questions and answers about the\nproject. If you have a question that isn't answered here, please\nopen a discussion."},{"heading":"stepperize-faq","content":"Yes, you can use Stepperize with React or any other React framework"},{"heading":"stepperize-faq","content":"Not at the moment. Initially Stepperize has a library called @stepperize/react, but we hope that the\ncommunity can contribute with different implementations for the other frameworks with @stepperize/vue,\n@stepperize/solid, etc."},{"heading":"stepperize-faq","content":"Yes, even all the examples you will see in the documentation are made with Shadcn."},{"heading":"stepperize-faq","content":"Yes, as Stepperize is a headless component, you can use it as you wish and style it as you wish.\nFun fact: this library was born as a PR for Shadcn UI."},{"heading":"stepperize-faq","content":"Yes, Stepperize is a headless component, so you can create your own logic and use the component as you wish."}],"headings":[{"id":"thinking-in-steps","content":"Thinking in Steps"},{"id":"common-use-cases-for-steppers","content":"Common Use Cases for Steppers"},{"id":"thinking-in-flows","content":"Thinking in Flows"},{"id":"using-stepperize-for-flow-management","content":"Using Stepperize for Flow Management"},{"id":"stepperize-faq","content":"Stepperize FAQ"}]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/installation.mdx","data":{"lastModified":1726164504000,"frontmatter":{"title":"Installation","description":"Learn how to install @stepperize/react library","icon":"Rocket"},"toc":[],"structuredData":{"contents":[{"heading":"","content":"You can install using NPM, Yarn, PNPM or Bun."}],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/api-references/define.mdx","data":{"lastModified":1726164504000,"frontmatter":{"title":"Define","description":"How to define a stepper"},"toc":[{"title":"Creating our steps","url":"#creating-our-steps","depth":2},{"title":"Import the constructor","url":"#import-the-constructor","depth":3},{"title":"Create the steps","url":"#create-the-steps","depth":3}],"structuredData":{"contents":[{"heading":"","content":"The main idea is that we can define our IDs that will identify each step.\nWhen we define the steps, we get an object that contains everything we need to build our stepper."},{"heading":"import-the-constructor","content":"In order to create our steps we need to import the defineSteps from the library."},{"heading":"create-the-steps","content":"defineStepper is a function that allows us to get a Provider, a hook and the array of steps we are using.\nThe only mandatory value for each step is the id. Then, we can add whatever we need and this will be typesafe when we use the hook."},{"heading":"create-the-steps","content":"With this we have everything we need to be able to build our own Stepper with the styles and logic we want."},{"heading":"create-the-steps","content":"Read more about the use of the different parts here:"},{"heading":"create-the-steps","content":"Hook"},{"heading":"create-the-steps","content":"Scoped"}],"headings":[{"id":"creating-our-steps","content":"Creating our steps"},{"id":"import-the-constructor","content":"Import the constructor"},{"id":"create-the-steps","content":"Create the steps"}]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/api-references/hook.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Hook","description":"How to get access to all the methods of our defineStepper to be able to build our own stepper"},"toc":[{"title":"Usage","url":"#usage","depth":2},{"title":"How to render content","url":"#how-to-render-content","depth":2},{"title":"when","url":"#when","depth":3},{"title":"switch","url":"#switch","depth":3},{"title":"match","url":"#match","depth":3},{"title":"API","url":"#api","depth":2}],"structuredData":{"contents":[{"heading":"","content":"The useStepper hook provides access to the actions needed to interact with the stepper.\nIt can be used with or without the Scoped component, but in this case it will be used without Scoped."},{"heading":"","content":"If you want to know how to use the stepper with the Scoped component, you can read the Scoped section."},{"heading":"how-to-render-content","content":"In Stepperize there are different patterns for rendering components or content within each step."},{"heading":"when","content":"The when function allows to render a component when the stepper is in a specific step."},{"heading":"when","content":"This function receives 3 parameters:"},{"heading":"when","content":"The first parameter is the step ID."},{"heading":"when","content":"The second parameter is a function that returns the component to render when the step matches the given ID."},{"heading":"when","content":"The third parameter is a function that returns the component to render when the step does not match the given ID."},{"heading":"when","content":"Also, you can use the when with the third parameter to render a component when the step is not in a specific step."},{"heading":"switch","content":"Like when, switch allows components to be rendered when the step id is matched,\nbut following the switch logical control structure."},{"heading":"switch","content":"This function receives an object with the step ID as the key and a function that returns\nthe component to render when the step matches the given ID."},{"heading":"match","content":"The match function allows to render a component when the stepper is in a specific step."},{"heading":"match","content":"Unlike when and switch, match does not allow a component to be rendered when the stepper is in a specific step.\nInstead, it allows a component to be rendered when the stepper is in a specific state."},{"heading":"match","content":"This allows us to have a state-based control that can come from either the client or the server side."},{"heading":"match","content":"Think of frameworks like Remix where you can have state management from the server with loaders and actions."},{"heading":"match","content":"This function receives 2 parameters:"},{"heading":"match","content":"The first parameter is the step ID."},{"heading":"match","content":"The second parameter is a function that returns the component to render when the step matches the given ID."},{"heading":"api","content":"The useStepper hook returns an object with the following properties:"}],"headings":[{"id":"usage","content":"Usage"},{"id":"how-to-render-content","content":"How to render content"},{"id":"when","content":"when"},{"id":"switch","content":"switch"},{"id":"match","content":"match"},{"id":"api","content":"API"}]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/api-references/scoped.mdx","data":{"lastModified":1726164504000,"frontmatter":{"title":"Scoped","description":"How to get access to the useStepper hook in a child component"},"toc":[{"title":"Usage","url":"#usage","depth":2},{"title":"API Reference","url":"#api-reference","depth":2},{"title":"Multiple Scopes","url":"#multiple-scopes","depth":2}],"structuredData":{"contents":[{"heading":"","content":"The Scoped component works as a provider and allows us to synchronise the state of steps via useStepper between child components."},{"heading":"usage","content":"Then, in the child component, we can use the useStepper hook to get the steps and use them."},{"heading":"usage","content":"The Scoped component is only necessary if we want a child component to have\naccess to the steps. Otherwise, we can use the hook directly at the same level\nwhere we render our code."},{"heading":"multiple-scopes","content":"We can have multiple scopes in our application. For example, we can have a global scope and a local scope."},{"heading":"multiple-scopes","content":"Finally, we can use the Global.useStepper on all children of GlobalStepper.Scoped and Local.useStepper on all children of LocalStepper.Scoped."}],"headings":[{"id":"usage","content":"Usage"},{"id":"api-reference","content":"API Reference"},{"id":"multiple-scopes","content":"Multiple Scopes"}]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/migration/migrating-to-v2.mdx","data":{"lastModified":1726164504000,"frontmatter":{"title":"Migrating to v2","description":"Learn how to migrate from v1 to v2","icon":"CircleFadingArrowUp"},"toc":[{"title":"Breaking Changes","url":"#breaking-changes","depth":2},{"title":"defineSteps helper","url":"#definesteps-helper","depth":3},{"title":"Stepper Provider","url":"#stepper-provider","depth":3},{"title":"useStepper hook","url":"#usestepper-hook","depth":3}],"structuredData":{"contents":[{"heading":"","content":"Stepperize v2 is a complete rewrite of the original Stepperize library. It comes with a few breaking changes and new features."},{"heading":"definesteps-helper","content":"The defineSteps function has been removed. Use defineStepper instead."},{"heading":"definesteps-helper","content":"Also, defineStepper only requires one id for each step and the type Step no longer\nhas any other value, since you can send it anything else in favour of automatic inference."},{"heading":"definesteps-helper","content":"For more information, see the Define section."},{"heading":"stepper-provider","content":"The Stepper component has been removed. Use Scoped from defineStepper object instead if you want to use with 1 or more Scopes of steps."},{"heading":"stepper-provider","content":"We don't need to pass the array of steps to the component anymore."},{"heading":"stepper-provider","content":"The Stepper component only accepts one prop, initialStep, which is the initial step to be active initially."},{"heading":"stepper-provider","content":"For more information, see the Scoped section."},{"heading":"usestepper-hook","content":"The useStepper hook has been removed. Use useStepper from defineStepper instead."},{"heading":"usestepper-hook","content":"For more information, see the Hook section."}],"headings":[{"id":"breaking-changes","content":"Breaking Changes"},{"id":"definesteps-helper","content":"defineSteps helper"},{"id":"stepper-provider","content":"Stepper Provider"},{"id":"usestepper-hook","content":"useStepper hook"}]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/migration/migrating-to-v3.mdx","data":{"lastModified":1726164504000,"frontmatter":{"title":"Migrating to v3","description":"Learn how to migrate from v2 to v3","icon":"CircleFadingArrowUp"},"toc":[{"title":"Breaking Changes","url":"#breaking-changes","depth":2},{"title":"Name changes in the values returned by the hook","url":"#name-changes-in-the-values-returned-by-the-hook","depth":3},{"title":"New Features","url":"#new-features","depth":2},{"title":"New switch method","url":"#new-switch-method","depth":3},{"title":"Add all property","url":"#add-all-property","depth":3}],"structuredData":{"contents":[{"heading":"","content":"Stepperize v3 brings with it a number of naming changes to make the pattern.\nIt also adds a switch method that allows to render in a simpler way the components we want for each step."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"The values returned by the useStepper hook have been renamed to make the pattern more consistent."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"currentStep is now current."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"isFirstStep is now isFirst."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"isLastStep is now isLast."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"getStepById is now get."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"goToNextStep is now next."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"goToPrevStep is now prev."},{"heading":"name-changes-in-the-values-returned-by-the-hook","content":"goToStep is now goTo."},{"heading":"new-switch-method","content":"The switch method has been added to the useStepper hook. This method allows us to render the components we want for each step in a simpler way."},{"heading":"add-all-property","content":"The all property has been added to the object returned by the useStepper hook. This property contains all the steps in the stepper."}],"headings":[{"id":"breaking-changes","content":"Breaking Changes"},{"id":"name-changes-in-the-values-returned-by-the-hook","content":"Name changes in the values returned by the hook"},{"id":"new-features","content":"New Features"},{"id":"new-switch-method","content":"New switch method"},{"id":"add-all-property","content":"Add all property"}]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/basic.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Basic Usage","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/conform-react.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Conform React","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/dialog.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Dialog","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/multi-scoped.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Multi-scoped","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/query-params.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Query Params","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/react-hook-form.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"React Hook Form","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/scoped.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Scoped","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"},{"path":"/Users/damianricobelli/Desktop/Personal/stepperize/apps/docs/content/docs/react/usage/shareable-data.mdx","data":{"lastModified":1727411570000,"frontmatter":{"title":"Shareable Data","description":"Coming soon..."},"toc":[],"structuredData":{"contents":[],"headings":[]}},"collection":"docs"}]} \ No newline at end of file diff --git a/apps/docs/.source/source.config.mjs b/apps/docs/.source/source.config.mjs new file mode 100644 index 0000000..edce62b --- /dev/null +++ b/apps/docs/.source/source.config.mjs @@ -0,0 +1,25 @@ +// source.config.ts +import { rehypeCodeDefaultOptions } from "fumadocs-core/mdx-plugins"; +import { defineConfig, defineDocs } from "fumadocs-mdx/config"; +import { transformerTwoslash } from "fumadocs-twoslash"; +var { docs, meta } = defineDocs(); +var source_config_default = defineConfig({ + generateManifest: true, + lastModifiedTime: "git", + mdxOptions: { + rehypeCodeOptions: { + inline: "tailing-curly-colon", + themes: { + light: "catppuccin-latte", + dark: "catppuccin-mocha" + }, + //@ts-ignore + transformers: [...rehypeCodeDefaultOptions.transformers ?? [], transformerTwoslash()] + } + } +}); +export { + source_config_default as default, + docs, + meta +}; diff --git a/docs/CHANGELOG.md b/apps/docs/CHANGELOG.md similarity index 100% rename from docs/CHANGELOG.md rename to apps/docs/CHANGELOG.md diff --git a/apps/docs/README.md b/apps/docs/README.md new file mode 100644 index 0000000..69c81d2 --- /dev/null +++ b/apps/docs/README.md @@ -0,0 +1,26 @@ +# docs-2 + +This is a Next.js application generated with +[Create Fumadocs](https://github.com/fuma-nama/fumadocs). + +Run development server: + +```bash +npm run dev +# or +pnpm dev +# or +yarn dev +``` + +Open http://localhost:3000 with your browser to see the result. + +## Learn More + +To learn more about Next.js and Fumadocs, take a look at the following +resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js + features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- [Fumadocs](https://fumadocs.vercel.app) - learn about Fumadocs diff --git a/apps/docs/app/(home)/layout.tsx b/apps/docs/app/(home)/layout.tsx new file mode 100644 index 0000000..5c8cd64 --- /dev/null +++ b/apps/docs/app/(home)/layout.tsx @@ -0,0 +1,11 @@ +import { HomeLayout } from "fumadocs-ui/home-layout"; +import type { ReactNode } from "react"; +import { baseOptions } from "../layout.config"; + +export default function Layout({ + children, +}: { + children: ReactNode; +}): React.ReactElement { + return {children}; +} diff --git a/apps/docs/app/(home)/page.tsx b/apps/docs/app/(home)/page.tsx new file mode 100644 index 0000000..a9c8dcf --- /dev/null +++ b/apps/docs/app/(home)/page.tsx @@ -0,0 +1,74 @@ +import { HeroStepper } from "@/components/hero"; +import { HowItWorks } from "@/components/how-it-works"; +import Link from "next/link"; + +export default function HomePage() { + return ( +
+
+
+
+
+

+ The library for building step-by-step workflows +

+

+ Create and customize step flows for your web and mobile apps easily and 100% typesafe. +

+
+
+ + Get Started + + + GitHub + +
+
+
+
+ +
+
+
+
+ +
+
+

Ready to simplify your flows?

+

+ Start building intuitive, step-by-step workflows for your applications today. Stepperize makes it easy and + type-safe. +

+
+ + Get Started + + + GitHub + +
+
+
+
+
+

+ © {new Date().getFullYear()} Stepperize. All rights reserved. +

+
+
+
+ ); +} diff --git a/apps/docs/app/api/search/route.ts b/apps/docs/app/api/search/route.ts new file mode 100644 index 0000000..0c6ebf7 --- /dev/null +++ b/apps/docs/app/api/search/route.ts @@ -0,0 +1,12 @@ +import { source } from "@/app/source"; +import { createSearchAPI } from "fumadocs-core/search/server"; + +export const { GET } = createSearchAPI("advanced", { + indexes: source.getPages().map((page) => ({ + title: page.data.title, + description: page.data.description, + structuredData: page.data.structuredData, + id: page.url, + url: page.url, + })), +}); diff --git a/docs/public/favicon.png b/apps/docs/app/apple-icon.png similarity index 100% rename from docs/public/favicon.png rename to apps/docs/app/apple-icon.png diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[[...slug]]/page.tsx new file mode 100644 index 0000000..bfb3746 --- /dev/null +++ b/apps/docs/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,79 @@ +import { source } from "@/app/source"; +import { useMDXComponents } from "@/mdx-components"; +import { createMetadata, metadataImage } from "@/utils/metadata"; +import defaultMdxComponents from "fumadocs-ui/mdx"; +import { DocsBody, DocsDescription, DocsPage, DocsTitle } from "fumadocs-ui/page"; +import type { Metadata } from "next"; +import { notFound } from "next/navigation"; + +interface Param { + slug: string[]; +} + +export default async function Page({ + params, +}: { + params: Param; +}) { + const page = source.getPage(params.slug); + if (!page) { + notFound(); + } + + const MDX = page.data.body; + + const components = useMDXComponents(defaultMdxComponents); + + const path = `apps/docs/content/docs/${page.file.path}`; + + return ( + + {page.data.title} + {page.data.description} + + + + + ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export function generateMetadata({ params }: { params: Param }): Metadata { + const page = source.getPage(params.slug); + + if (!page) { + notFound(); + } + + const description = page.data.description ?? "The library for building step-by-step workflows."; + + return createMetadata( + metadataImage.withImage(page.slugs, { + title: page.data.title, + description, + openGraph: { + url: `/docs/${page.slugs.join("/")}`, + }, + icons: { + icon: "/icon.png", + }, + }), + ); +} diff --git a/apps/docs/app/docs/layout.tsx b/apps/docs/app/docs/layout.tsx new file mode 100644 index 0000000..1191d88 --- /dev/null +++ b/apps/docs/app/docs/layout.tsx @@ -0,0 +1,7 @@ +import { DocsLayout } from "fumadocs-ui/layout"; +import type { ReactNode } from "react"; +import { docsOptions } from "../layout.config"; + +export default function Layout({ children }: { children: ReactNode }) { + return {children}; +} diff --git a/docs/public/favicon.svg b/apps/docs/app/favicon.svg similarity index 100% rename from docs/public/favicon.svg rename to apps/docs/app/favicon.svg diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css new file mode 100644 index 0000000..a0b7a61 --- /dev/null +++ b/apps/docs/app/global.css @@ -0,0 +1,84 @@ +@import "@radix-ui/colors/black-alpha.css"; +@import "@radix-ui/colors/white-alpha.css"; + +@import "@radix-ui/colors/slate.css"; +@import "@radix-ui/colors/slate-dark.css"; +@import "@radix-ui/colors/green.css"; +@import "@radix-ui/colors/green-dark.css"; +@import "@radix-ui/colors/yellow.css"; +@import "@radix-ui/colors/yellow-dark.css"; +@import "@radix-ui/colors/red.css"; +@import "@radix-ui/colors/red-dark.css"; +@import "@radix-ui/colors/blue.css"; +@import "@radix-ui/colors/blue-dark.css"; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --fd-layout-width: 1400px; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/apps/docs/app/icon.png b/apps/docs/app/icon.png new file mode 100644 index 0000000..dcd7820 Binary files /dev/null and b/apps/docs/app/icon.png differ diff --git a/apps/docs/app/layout.client.tsx b/apps/docs/app/layout.client.tsx new file mode 100644 index 0000000..d63ea1e --- /dev/null +++ b/apps/docs/app/layout.client.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { modes } from "@/lib/modes"; +import { cn } from "@/lib/utils"; +import { cva } from "class-variance-authority"; +import Link from "next/link"; +import { useParams } from "next/navigation"; +import type { ReactNode } from "react"; + +const itemVariants = cva("rounded-md px-2 py-1 transition-colors hover:text-fd-accent-foreground", { + variants: { + active: { + true: "bg-fd-accent text-fd-accent-foreground", + }, + }, +}); + +export function Body({ + children, +}: { + children: ReactNode; +}): React.ReactElement { + const mode = useMode(); + + return {children}; +} + +export function NavChildren(): React.ReactElement { + const mode = useMode(); + + return ( +
+ {modes.map((m) => ( + + {m.name} + + ))} +
+ ); +} + +export function useMode(): string | undefined { + const { slug } = useParams(); + return Array.isArray(slug) && slug.length > 0 ? slug[0] : undefined; +} diff --git a/apps/docs/app/layout.config.tsx b/apps/docs/app/layout.config.tsx new file mode 100644 index 0000000..7b79233 --- /dev/null +++ b/apps/docs/app/layout.config.tsx @@ -0,0 +1,51 @@ +import type { HomeLayoutProps } from "fumadocs-ui/home-layout"; +import type { DocsLayoutProps } from "fumadocs-ui/layout"; + +import { NavChildren } from "@/app/layout.client"; +import { source } from "@/app/source"; +import { modes } from "@/lib/modes"; +import { RootToggle } from "fumadocs-ui/components/layout/root-toggle"; +import { BookIcon, Waypoints } from "lucide-react"; + +export const baseOptions: HomeLayoutProps = { + githubUrl: "https://github.com/damianricobelli/stepperize", + nav: { + title: ( +
+ + Stepperize +
+ ), + transparentMode: "top", + children: , + }, + links: [ + { + icon: , + text: "Blog", + url: "/blog", + active: "nested-url", + }, + ], +}; + +export const docsOptions: DocsLayoutProps = { + ...baseOptions, + tree: source.pageTree, + nav: { + ...baseOptions.nav, + transparentMode: "none", + }, + sidebar: { + banner: ( + ({ + url: `/docs/${mode.param}`, + icon: , + title: mode.name, + description: mode.description, + }))} + /> + ), + }, +}; diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx new file mode 100644 index 0000000..4699208 --- /dev/null +++ b/apps/docs/app/layout.tsx @@ -0,0 +1,28 @@ +import { baseUrl, createMetadata } from "@/utils/metadata"; +import "./global.css"; +import { RootProvider } from "fumadocs-ui/provider"; +import { Inter } from "next/font/google"; +import type { ReactNode } from "react"; + +export const metadata = createMetadata({ + title: { + template: "%s | Stepperize", + default: "Stepperize", + }, + description: "The library for building step-by-step workflows.", + metadataBase: baseUrl, +}); + +const inter = Inter({ + subsets: ["latin"], +}); + +export default function Layout({ children }: { children: ReactNode }) { + return ( + + + {children} + + + ); +} diff --git a/docs/pages/api/Inter-SemiBold.otf b/apps/docs/app/og/[...slug]/Inter-SemiBold.otf similarity index 100% rename from docs/pages/api/Inter-SemiBold.otf rename to apps/docs/app/og/[...slug]/Inter-SemiBold.otf diff --git a/apps/docs/app/og/[...slug]/route.tsx b/apps/docs/app/og/[...slug]/route.tsx new file mode 100644 index 0000000..fdf4791 --- /dev/null +++ b/apps/docs/app/og/[...slug]/route.tsx @@ -0,0 +1,127 @@ +import { readFileSync } from "node:fs"; +import { metadataImage } from "@/utils/metadata"; +import { ImageResponse, type ImageResponse as ImageResponseType } from "next/og"; + +const inter = readFileSync("./app/og/[...slug]/Inter-SemiBold.otf"); + +export const GET = metadataImage.createAPI((page): ImageResponseType => { + return new ImageResponse( +
+
+ + {page.data.title} + + + + + + + + +
+ Stepperize +
+
+
+
+ + {page.data.title} + +
+
+ {page.data.description} +
+
+
, + { + width: 1200, + height: 630, + fonts: [ + { + name: "inter", + data: inter, + style: "normal", + }, + ], + }, + ); +}); + +export function generateStaticParams(): { + slug: string[]; +}[] { + return metadataImage.generateParams(); +} diff --git a/apps/docs/app/public/banner.png b/apps/docs/app/public/banner.png new file mode 100644 index 0000000..309d41d Binary files /dev/null and b/apps/docs/app/public/banner.png differ diff --git a/apps/docs/app/public/robots.txt b/apps/docs/app/public/robots.txt new file mode 100644 index 0000000..715dddc --- /dev/null +++ b/apps/docs/app/public/robots.txt @@ -0,0 +1,6 @@ +User-agent: * +Allow: / + +Host: https://stepperize.vercel.app + +Sitemap: https://stepperize.vercel.app/sitemap.xml diff --git a/apps/docs/app/sitemap.ts b/apps/docs/app/sitemap.ts new file mode 100644 index 0000000..b4e1305 --- /dev/null +++ b/apps/docs/app/sitemap.ts @@ -0,0 +1,26 @@ +import { source } from "@/app/source"; +import { baseUrl } from "@/utils/metadata"; +import type { MetadataRoute } from "next"; + +export default function sitemap(): MetadataRoute.Sitemap { + const url = (path: string): string => new URL(path, baseUrl).toString(); + + return [ + { + url: url("/"), + changeFrequency: "monthly", + priority: 1, + }, + { + url: url("/docs"), + changeFrequency: "monthly", + priority: 0.8, + }, + ...source.getPages().map((page) => ({ + url: url(page.url), + lastModified: page.data.lastModified ? new Date(page.data.lastModified) : undefined, + changeFrequency: "weekly", + priority: 0.5, + })), + ]; +} diff --git a/apps/docs/app/source.ts b/apps/docs/app/source.ts new file mode 100644 index 0000000..82ad7f9 --- /dev/null +++ b/apps/docs/app/source.ts @@ -0,0 +1,15 @@ +import { docs, meta } from "@/.source"; +import { create } from "@/components/create-icon"; +import { loader } from "fumadocs-core/source"; +import { createMDXSource } from "fumadocs-mdx"; +import { icons } from "lucide-react"; + +export const source = loader({ + baseUrl: "/docs", + source: createMDXSource(docs, meta), + icon(icon) { + if (icon && icon in icons) { + return create({ icon: icons[icon as keyof typeof icons] }); + } + }, +}); diff --git a/docs/components.json b/apps/docs/components.json similarity index 62% rename from docs/components.json rename to apps/docs/components.json index 19a1917..78f0b17 100644 --- a/docs/components.json +++ b/apps/docs/components.json @@ -5,13 +5,16 @@ "tsx": true, "tailwind": { "config": "tailwind.config.js", - "css": "app/globals.css", - "baseColor": "slate", + "css": "app/global.css", + "baseColor": "zinc", "cssVariables": true, "prefix": "" }, "aliases": { "components": "@/components", - "utils": "@/lib/utils" + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" } } \ No newline at end of file diff --git a/apps/docs/components/create-icon.tsx b/apps/docs/components/create-icon.tsx new file mode 100644 index 0000000..899f921 --- /dev/null +++ b/apps/docs/components/create-icon.tsx @@ -0,0 +1,14 @@ +import type { LucideIcon } from "lucide-react"; +import { TerminalIcon } from "lucide-react"; + +export function create({ + icon: Icon, +}: { + icon?: LucideIcon; +}): React.ReactElement { + return ( +
+ {Icon ? : } +
+ ); +} diff --git a/apps/docs/components/demo-viewer.tsx b/apps/docs/components/demo-viewer.tsx new file mode 100644 index 0000000..45d0910 --- /dev/null +++ b/apps/docs/components/demo-viewer.tsx @@ -0,0 +1,39 @@ +"use client"; + +import { Skeleton } from "@/components/ui/skeleton"; +import { cva } from "class-variance-authority"; +import { useEffect, useState } from "react"; + +export const DemoViewer = ({ src, className }: { src: string; className?: string }) => { + const [isLoaded, setIsLoaded] = useState(false); + + useEffect(() => { + setIsLoaded(false); + }, [src]); + + return ( + <> + {!isLoaded && ( + + Loading demo... + + )} +