diff --git a/rspack.config.js b/rspack.config.js
index e4fdee3..f39caee 100644
--- a/rspack.config.js
+++ b/rspack.config.js
@@ -20,6 +20,9 @@ module.exports = {
entry: {
main: "./src/main.bs.js",
},
+ devServer: {
+ historyApiFallback: true,
+ },
devtool: "source-map",
module: {
rules: [
diff --git a/src/App.res b/src/App.res
index aecc48a..27f4431 100644
--- a/src/App.res
+++ b/src/App.res
@@ -1,14 +1,5 @@
-// Import design system and components
open Emotion.Css
-// Import component library
-module Components = {
- module Button = Button.Button
- module Input = Input.Input
- module Card = Card.Card
- module Typography = Typography.Typography
-}
-
// Initialize global styles
let _ = GlobalStyles.initialize()
@@ -24,7 +15,7 @@ Emotion.Css.injectGlobal(`
will-change: filter;
}
.logo:hover {
- filter: drop-shadow(0 0 2em #c8a45caa);
+ filter: drop-shadow(0 0 2em ${Theme.Theme.Colors.brand["primary"]}aa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
@@ -47,7 +38,7 @@ Emotion.Css.injectGlobal(`
/* Hero section gradients */
.hero-gradient {
- background: linear-gradient(135deg, #c8a45c 0%, #c47d4a 100%);
+ background: linear-gradient(135deg, ${Theme.Theme.Colors.brand["primary"]} 0%, ${Theme.Theme.Colors.brand["secondary"]} 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@@ -66,251 +57,24 @@ Emotion.Css.injectGlobal(`
}
`)
-module Logo = {
- @module("./assets/react.svg") @react.component
- external make: (~role: string=?, ~className: string=?, ~alt: string=?, unit) => React.element =
- "default"
-}
-
-// Homepage sections
-module HeroSection = {
- @react.component
- let make = () => {
- let (count, setCount) = React.useState(() => 0)
-
- let heroStyles = css({
- "minHeight": "80vh",
- "display": "flex",
- "flexDirection": "column",
- "alignItems": "center",
- "justifyContent": "center",
- "textAlign": "center",
- "padding": "2rem 1rem",
- "background": "linear-gradient(180deg, rgba(200, 164, 92, 0.04) 0%, transparent 100%)"
- })
-
- let logoContainerStyles = css({
- "display": "flex",
- "gap": "2rem",
- "marginBottom": "2rem",
- "alignItems": "center"
- })
-
-
-
-
-
- {React.string("Modern React Development")}
-
-
-
- {React.string("Built with Rspack, ReScript, React, and Bun for lightning-fast development")}
-
-
-
- setCount(prev => prev + 1)}>
- {React.string("Interactive Demo (" ++ Int.toString(count) ++ ")")}
-
-
- {React.string("View Components")}
-
-
-
- }
-}
-
-module FeaturesSection = {
- @react.component
- let make = () => {
- let sectionStyles = css({
- "padding": "4rem 1rem",
- "maxWidth": "1200px",
- "margin": "0 auto"
- })
-
- let gridStyles = css({
- "display": "grid",
- "gridTemplateColumns": "repeat(auto-fit, minmax(300px, 1fr))",
- "gap": "2rem",
- "marginTop": "3rem"
- })
-
- let features = [
- ("⚡ Lightning Fast", "Built with Rspack for ultra-fast bundling and hot reload"),
- ("🔧 Type Safety", "ReScript provides bulletproof type safety and excellent ergonomics"),
- ("🎨 Design System", "Comprehensive component library with consistent styling"),
- ("🚀 Modern Stack", "Latest React, Emotion CSS-in-JS, and Bun package manager")
- ]
-
-
-
- {React.string("Why This Template?")}
-
-
-
- {features
- ->Belt.Array.map(((title, description)) => {
-
-
- {React.string(title)}
-
-
- {React.string(description)}
-
-
- })
- ->React.array}
-
-
- }
-}
-
-module ComponentsSection = {
- @react.component
- let make = () => {
- let (inputValue, setInputValue) = React.useState(() => "")
- let (_selectedCard, _setSelectedCard) = React.useState(() => None)
-
- let sectionStyles = css({
- "padding": "4rem 1rem",
- "backgroundColor": `${Theme.Theme.Colors.background["elevated"]}80`,
- "borderTop": `1px solid ${Theme.Theme.Colors.border["default"]}`
- })
-
- let containerStyles = css({
- "maxWidth": "1200px",
- "margin": "0 auto"
- })
-
- let demoGridStyles = css({
- "display": "grid",
- "gridTemplateColumns": "repeat(auto-fit, minmax(350px, 1fr))",
- "gap": "2rem",
- "marginTop": "3rem"
- })
-
-
-
-
- {React.string("Component Library")}
-
-
-
- {React.string("Explore our comprehensive component library with variants, sizes, and states")}
-
-
-
- // Button Variants Demo
-
-
-
- {React.string("Button Variants")}
-
-
-
-
-
- {React.string("Primary")}
-
-
- {React.string("Secondary")}
-
-
- {React.string("Outline")}
-
-
- {React.string("Ghost")}
-
-
- {React.string("Danger")}
-
-
-
-
-
- // Input Variants Demo
-
-
-
- {React.string("Input Variants")}
-
-
-
-
- {
- let value = ReactEvent.Form.target(evt)["value"]
- setInputValue(_ => value)
- }}
- />
-
-
-
-
-
-
-
- // Typography Demo
-
-
-
- {React.string("Typography System")}
-
-
-
-
-
- {React.string("Display Text")}
-
-
- {React.string("Heading Text")}
-
-
- {React.string("Body text with proper line height and spacing for optimal readability.")}
-
-
- {React.string("Caption text for additional information")}
-
-
-
-
-
-
-
- }
-}
-
module App = {
@react.component
let make = () => {
-
-
-
-
-
-
+
+
+
+
+
+
{React.string("Built with Rspack + ReScript + React + Bun")}
-
+
}
diff --git a/src/Router.res b/src/Router.res
new file mode 100644
index 0000000..d76e11a
--- /dev/null
+++ b/src/Router.res
@@ -0,0 +1,43 @@
+open Emotion.Css
+
+module NotFound = {
+ @react.component
+ let make = () => {
+ let containerStyles = css({
+ "padding": "4rem 1rem",
+ "maxWidth": "600px",
+ "margin": "0 auto",
+ "textAlign": "center",
+ })
+
+
+
+ {React.string("404")}
+
+
+ {React.string("Page not found.")}
+
+
+ RescriptReactRouter.push("/")}>
+ {React.string("Go Home")}
+
+
+
+ }
+}
+
+@react.component
+let make = () => {
+ let url = RescriptReactRouter.useUrl()
+
+ switch url.path {
+ | list{} =>
+ | list{"components"} =>
+ | list{"posts"} =>
+ | list{"login"} =>
+ | _ =>
+ }
+}
diff --git a/src/components/NavBar/NavBar.res b/src/components/NavBar/NavBar.res
new file mode 100644
index 0000000..dd4cece
--- /dev/null
+++ b/src/components/NavBar/NavBar.res
@@ -0,0 +1,88 @@
+open Emotion.Css
+open Emotion.Utils
+
+module NavBar = {
+ @react.component
+ let make = () => {
+ let url = RescriptReactRouter.useUrl()
+ let currentPath = switch url.path {
+ | list{} => "/"
+ | list{segment, ..._} => "/" ++ segment
+ }
+
+ let navStyles = css({
+ "display": "flex",
+ "alignItems": "center",
+ "justifyContent": "space-between",
+ "padding": "1rem 2rem",
+ "borderBottom": `1px solid ${Color.border}`,
+ "backgroundColor": Color.bgPrimary,
+ "position": "sticky",
+ "top": "0",
+ "zIndex": "100",
+ })
+
+ let brandStyles = css({
+ "fontSize": "1.25rem",
+ "fontWeight": "700",
+ "color": Color.textPrimary,
+ "cursor": "pointer",
+ "textDecoration": "none",
+ })
+
+ let linksStyles = css({
+ "display": "flex",
+ "gap": "1.5rem",
+ "alignItems": "center",
+ })
+
+ let linkStyles = (~active) =>
+ css({
+ "color": active ? Color.primary : Color.textSecondary,
+ "textDecoration": "none",
+ "fontWeight": active ? "600" : "400",
+ "fontSize": "0.9375rem",
+ "cursor": "pointer",
+ "transition": "color 200ms ease-out",
+ "borderBottom": active ? `2px solid ${Color.primary}` : "2px solid transparent",
+ "paddingBottom": "0.25rem",
+ })
+
+ let handleNav = (path, evt: ReactEvent.Mouse.t) => {
+ evt->ReactEvent.Mouse.preventDefault
+ RescriptReactRouter.push(path)
+ }
+
+
+ handleNav("/", evt)}>
+ {React.string("Rspack + ReScript")}
+
+
+
+ }
+}
diff --git a/src/pages/ComponentsPage.res b/src/pages/ComponentsPage.res
new file mode 100644
index 0000000..4812866
--- /dev/null
+++ b/src/pages/ComponentsPage.res
@@ -0,0 +1,120 @@
+open Emotion.Css
+
+module Components = {
+ module Button = Button.Button
+ module Input = Input.Input
+ module Card = Card.Card
+ module Typography = Typography.Typography
+}
+
+@react.component
+let make = () => {
+ let (inputValue, setInputValue) = React.useState(() => "")
+
+ let sectionStyles = css({
+ "padding": "4rem 1rem",
+ "maxWidth": "1200px",
+ "margin": "0 auto",
+ })
+
+ let demoGridStyles = css({
+ "display": "grid",
+ "gridTemplateColumns": "repeat(auto-fit, minmax(350px, 1fr))",
+ "gap": "2rem",
+ "marginTop": "3rem",
+ })
+
+
+
+ {React.string("Component Library")}
+
+
+ {React.string("Explore our comprehensive component library with variants, sizes, and states")}
+
+
+
+
+
+ {React.string("Button Variants")}
+
+
+
+
+
+ {React.string("Primary")}
+
+
+ {React.string("Secondary")}
+
+
+ {React.string("Outline")}
+
+
+ {React.string("Ghost")}
+
+
+ {React.string("Danger")}
+
+
+
+
+
+
+
+ {React.string("Input Variants")}
+
+
+
+
+ {
+ let value = ReactEvent.Form.target(evt)["value"]
+ setInputValue(_ => value)
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ {React.string("Typography System")}
+
+
+
+
+
+ {React.string("Display Text")}
+
+
+ {React.string("Heading Text")}
+
+
+ {React.string(
+ "Body text with proper line height and spacing for optimal readability.",
+ )}
+
+
+ {React.string("Caption text for additional information")}
+
+
+
+
+
+
+}
diff --git a/src/pages/HomePage.res b/src/pages/HomePage.res
new file mode 100644
index 0000000..49e13cb
--- /dev/null
+++ b/src/pages/HomePage.res
@@ -0,0 +1,127 @@
+open Emotion.Css
+
+module Components = {
+ module Button = Button.Button
+ module Typography = Typography.Typography
+ module Card = Card.Card
+}
+
+module Logo = {
+ @module("../assets/react.svg") @react.component
+ external make: (~role: string=?, ~className: string=?, ~alt: string=?, unit) => React.element =
+ "default"
+}
+
+module HeroSection = {
+ @react.component
+ let make = () => {
+ let (count, setCount) = React.useState(() => 0)
+
+ let heroStyles = css({
+ "minHeight": "80vh",
+ "display": "flex",
+ "flexDirection": "column",
+ "alignItems": "center",
+ "justifyContent": "center",
+ "textAlign": "center",
+ "padding": "2rem 1rem",
+ "background": `linear-gradient(180deg, ${Theme.Theme.Colors.brand["primary"]}0a 0%, transparent 100%)`,
+ })
+
+ let logoContainerStyles = css({
+ "display": "flex",
+ "gap": "2rem",
+ "marginBottom": "2rem",
+ "alignItems": "center",
+ })
+
+
+
+
+ {React.string("Modern React Development")}
+
+
+ {React.string("Built with Rspack, ReScript, React, and Bun for lightning-fast development")}
+
+
+ setCount(prev => prev + 1)}>
+ {React.string("Interactive Demo (" ++ Int.toString(count) ++ ")")}
+
+
+ {React.string("View Components")}
+
+
+
+ }
+}
+
+module FeaturesSection = {
+ @react.component
+ let make = () => {
+ let sectionStyles = css({
+ "padding": "4rem 1rem",
+ "maxWidth": "1200px",
+ "margin": "0 auto",
+ })
+
+ let gridStyles = css({
+ "display": "grid",
+ "gridTemplateColumns": "repeat(auto-fit, minmax(300px, 1fr))",
+ "gap": "2rem",
+ "marginTop": "3rem",
+ })
+
+ let features = [
+ ("Lightning Fast", "Built with Rspack for ultra-fast bundling and hot reload"),
+ ("Type Safety", "ReScript provides bulletproof type safety and excellent ergonomics"),
+ ("Design System", "Comprehensive component library with consistent styling"),
+ ("Modern Stack", "Latest React, Emotion CSS-in-JS, and Bun package manager"),
+ ]
+
+
+
+ {React.string("Why This Template?")}
+
+
+ {features
+ ->Belt.Array.map(((title, description)) => {
+
+
+ {React.string(title)}
+
+
+ {React.string(description)}
+
+
+ })
+ ->React.array}
+
+
+ }
+}
+
+@react.component
+let make = () => {
+
+
+
+
+}
diff --git a/src/pages/LoginPage.res b/src/pages/LoginPage.res
new file mode 100644
index 0000000..f9abdc2
--- /dev/null
+++ b/src/pages/LoginPage.res
@@ -0,0 +1,21 @@
+open Emotion.Css
+
+module Typography = Typography.Typography
+
+@react.component
+let make = () => {
+ let containerStyles = css({
+ "padding": "4rem 1rem",
+ "maxWidth": "400px",
+ "margin": "0 auto",
+ "textAlign": "center",
+ })
+
+
+ {React.string("Sign In")}
+
+ {React.string("Authentication with OAuth PKCE will be added here.")}
+
+
+}
diff --git a/src/pages/PostsPage.res b/src/pages/PostsPage.res
new file mode 100644
index 0000000..72f9b89
--- /dev/null
+++ b/src/pages/PostsPage.res
@@ -0,0 +1,21 @@
+open Emotion.Css
+
+module Typography = Typography.Typography
+
+@react.component
+let make = () => {
+ let containerStyles = css({
+ "padding": "4rem 1rem",
+ "maxWidth": "800px",
+ "margin": "0 auto",
+ "textAlign": "center",
+ })
+
+
+ {React.string("Posts")}
+
+ {React.string("Data fetching with Relay will be added here.")}
+
+
+}