diff --git a/package.json b/package.json
index 21f67781..9ca808dc 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"git-info": "rm -rf src/generated/ && mkdir src/generated/ && echo export default \"{\\\"commitHash\\\": \\\"$(git rev-parse --short HEAD)\\\", \\\"version\\\": \\\"$(git describe --tags --always)\\\"};\" > src/generated/gitInfo.ts"
},
"dependencies": {
- "@stellar/design-system": "^1.1.2",
+ "@stellar/design-system": "^2.0.0-beta.1",
"next": "14.0.4",
"react": "^18",
"react-dom": "^18"
diff --git a/src/app/(sidebar)/account/create/page.tsx b/src/app/(sidebar)/account/create/page.tsx
new file mode 100644
index 00000000..3aa44803
--- /dev/null
+++ b/src/app/(sidebar)/account/create/page.tsx
@@ -0,0 +1,5 @@
+"use client";
+
+export default function CreateAccount() {
+ return
-
{children}
+
+ {children}
diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx
new file mode 100644
index 00000000..0195d480
--- /dev/null
+++ b/src/app/not-found.tsx
@@ -0,0 +1,15 @@
+"use client";
+
+import Link from "next/link";
+
+import { Routes } from "@/constants/routes";
+
+export default function NotFound() {
+ return (
+
+
Not Found
+
Could not find requested resource
+
Return Home
+
+ );
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 5a7ab853..c9fb33c7 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,7 +1,11 @@
"use client";
-import { Layout } from "@stellar/design-system";
-
-export default function Home() {
- return
Page;
+export default function Introduction() {
+ return (
+
+ );
}
diff --git a/src/app/ui/MainLayout.tsx b/src/app/ui/MainLayout.tsx
deleted file mode 100644
index 4c48d93e..00000000
--- a/src/app/ui/MainLayout.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-"use client";
-
-import { ReactNode } from "react";
-import { Layout } from "@stellar/design-system";
-
-export const MainLayout = ({ children }: { children: ReactNode }) => {
- return (
- <>
-
-
{children}
-
- >
- );
-};
diff --git a/src/components/LayoutMain.tsx b/src/components/LayoutMain.tsx
new file mode 100644
index 00000000..05fd6127
--- /dev/null
+++ b/src/components/LayoutMain.tsx
@@ -0,0 +1,31 @@
+"use client";
+
+import { ReactNode } from "react";
+import Link from "next/link";
+
+import { ProjectLogo, ThemeSwitch } from "@stellar/design-system";
+
+import { MainNav } from "@/components/MainNav";
+
+export const LayoutMain = ({ children }: { children: ReactNode }) => {
+ return (
+ <>
+
+
+ {children}
+ >
+ );
+};
diff --git a/src/components/LayoutSidebar.tsx b/src/components/LayoutSidebar.tsx
new file mode 100644
index 00000000..f244d74b
--- /dev/null
+++ b/src/components/LayoutSidebar.tsx
@@ -0,0 +1,7 @@
+"use client";
+
+import { ReactNode } from "react";
+
+export const LayoutSidebar = ({ children }: { children: ReactNode }) => {
+ return
{children}
;
+};
diff --git a/src/components/LayoutSidebarContent.tsx b/src/components/LayoutSidebarContent.tsx
new file mode 100644
index 00000000..7bcc8cfb
--- /dev/null
+++ b/src/components/LayoutSidebarContent.tsx
@@ -0,0 +1,77 @@
+"use client";
+
+import { ReactNode } from "react";
+import { usePathname } from "next/navigation";
+import NextLink from "next/link";
+import { Routes } from "@/constants/routes";
+import { Icon } from "@stellar/design-system";
+
+export type SidebarLink = {
+ route: Routes | string;
+ label: string;
+ icon?: ReactNode;
+ nestedItems?: SidebarLink[];
+};
+
+export type Sidebar = {
+ navItems: SidebarLink[];
+ instruction?: string;
+ bottomItems?: SidebarLink[];
+};
+
+export const LayoutSidebarContent = ({
+ children,
+ sidebar,
+}: {
+ children: ReactNode;
+ sidebar: Sidebar;
+}) => {
+ const pathname = usePathname();
+
+ const Link = ({ item }: { item: SidebarLink }) => (
+
+ {item.icon ?? null} {item.label}
+
+ );
+
+ return (
+ <>
+
+
+ {/* TODO: add instruction */}
+ {/* TODO: render nested items */}
+
+ {sidebar.navItems.map((item) => (
+
+ ))}
+
+
+
+ {sidebar.bottomItems?.map((bi) => (
+
+ ))}
+
+
+
+ Got product feedback?
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/components/MainNav.tsx b/src/components/MainNav.tsx
new file mode 100644
index 00000000..b2ecc2e4
--- /dev/null
+++ b/src/components/MainNav.tsx
@@ -0,0 +1,78 @@
+import NextLink from "next/link";
+import { usePathname } from "next/navigation";
+
+import { Routes } from "@/constants/routes";
+
+type NavLink = {
+ href: Routes | string;
+ label: string;
+};
+
+const primaryNavLinks: NavLink[] = [
+ {
+ href: Routes.ROOT,
+ label: "Introduction",
+ },
+ {
+ href: Routes.CREATE_ACCOUNT,
+ label: "Account",
+ },
+ {
+ href: Routes.EXPLORE_ENDPOINTS,
+ label: "Explore Endpoints",
+ },
+];
+
+const secondaryNavLinks = [
+ {
+ href: "https://developers.stellar.org/docs",
+ label: "View Documentation",
+ },
+];
+
+export const MainNav = () => {
+ const pathname = usePathname();
+
+ const externalLinkProps = (href: string) => {
+ const isExternalLink = href?.startsWith("http") || href?.startsWith("//");
+
+ return isExternalLink
+ ? { rel: "noreferrer noopener", target: "_blank" }
+ : {};
+ };
+
+ const isActiveRoute = (link: string) => {
+ if (link.startsWith("http")) {
+ return false;
+ }
+
+ return pathname.split("/")[1] === link.split("/")[1];
+ };
+
+ const NavItem = ({ link }: { link: NavLink }) => (
+
+ {link.label}
+
+ );
+
+ return (
+
+ );
+};
diff --git a/src/components/NavLink.tsx b/src/components/NavLink.tsx
new file mode 100644
index 00000000..a64c647d
--- /dev/null
+++ b/src/components/NavLink.tsx
@@ -0,0 +1,11 @@
+import NextLink from "next/link";
+import { Props as LinkProps, Link } from "@stellar/design-system";
+
+/** Use `NavLink` instead of `Link` from Stellar Design System to support client-side routing. `NavLink` uses `Link` from `next/link` internally. */
+export const NavLink = (props: LinkProps) => {
+ return (
+
}>
+ {props.children}
+
+ );
+};
diff --git a/src/constants/routes.ts b/src/constants/routes.ts
new file mode 100644
index 00000000..c5524e5e
--- /dev/null
+++ b/src/constants/routes.ts
@@ -0,0 +1,10 @@
+export enum Routes {
+ ROOT = "/",
+ // Account
+ CREATE_ACCOUNT = "/account/create",
+ FUND_ACCOUNT = "/account/fund",
+ CREATE_MUXED_ACCOUNT = "/account/muxed-create",
+ PARSE_MUXED_ACCOUNT = "/account/muxed-parse",
+ // Explore Endpoints
+ EXPLORE_ENDPOINTS = "/explore-endpoints",
+}
diff --git a/src/styles/globals.scss b/src/styles/globals.scss
new file mode 100644
index 00000000..a82f3daa
--- /dev/null
+++ b/src/styles/globals.scss
@@ -0,0 +1,203 @@
+@use "./utils.scss" as *;
+
+// Fonts for SDS
+@import url("https://fonts.googleapis.com/css2?family=Inter+Tight&family=Inter:wght@400;500;600&family=Roboto+Mono&display=swap");
+
+// Layout
+#root {
+ &.LabLayout {
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto 1fr;
+ height: 100vh;
+ overflow: hidden;
+ min-width: 0;
+ min-height: 0;
+ }
+}
+
+.LabLayout {
+ color: var(--sds-clr-gray-11);
+ background-color: var(--sds-clr-gray-02);
+
+ // Header
+ &__header {
+ background-color: var(--sds-clr-gray-01);
+ border-bottom: 1px solid var(--sds-clr-gray-06);
+
+ &__main {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: pxToRem(16px);
+ padding: pxToRem(32px);
+ }
+
+ &__settings {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ flex: 1;
+ gap: pxToRem(12px);
+ }
+
+ &__nav {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: pxToRem(16px);
+ padding: 0 pxToRem(32px);
+
+ font-size: pxToRem(14px);
+ line-height: pxToRem(20px);
+ font-weight: var(--sds-fw-medium);
+ margin-bottom: -1px;
+
+ & > div {
+ display: flex;
+ gap: pxToRem(20px);
+ flex: 1;
+ }
+
+ &--secondary {
+ justify-content: flex-end;
+ }
+ }
+ }
+
+ // Sidebar layout
+ &__withSidebar {
+ display: grid;
+ grid-template-columns:
+ pxToRem(296px)
+ 1fr;
+ overflow: hidden;
+ }
+
+ // Content
+ &__container {
+ padding: pxToRem(32px);
+ overflow-x: auto;
+ }
+
+ &__content {
+ width: pxToRem(672px);
+ position: relative;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ gap: pxToRem(12px);
+ }
+
+ // Sideber
+ &__sidebar {
+ min-height: 0;
+ background-color: var(--sds-clr-gray-01);
+ border-right: 1px solid var(--sds-clr-gray-06);
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows:
+ minmax(0, max-content)
+ 1fr;
+
+ &--top {
+ overflow-x: auto;
+ padding: pxToRem(32px);
+ padding-bottom: pxToRem(16px);
+ display: flex;
+ flex-direction: column;
+ gap: pxToRem(8px);
+ flex: 1;
+ }
+
+ &--bottom {
+ --Sidebar-bottomItems-border-color: transparent;
+
+ flex-grow: 1;
+ flex-shrink: 0;
+ border-top: 1px solid var(--Sidebar-bottomItems-border-color);
+ background-color: var(--sds-clr-gray-01);
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ gap: pxToRem(8px);
+ padding-top: pxToRem(16px);
+ padding-bottom: pxToRem(32px);
+ margin-left: pxToRem(32px);
+ margin-right: pxToRem(32px);
+
+ &--border {
+ --Sidebar-bottomItems-border-color: var(--sds-clr-gray-06);
+ }
+ }
+
+ &__wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: pxToRem(8px);
+ }
+ }
+}
+
+// TODO: update name
+.NavLink {
+ --Nav-navLink-color: var(--sds-clr-gray-11);
+ --Nav-navLink-border-color: transparent;
+
+ color: var(--Nav-navLink-color);
+ text-decoration: none;
+ padding: pxToRem(12px) 0;
+ transition:
+ color var(--sds-anim-transition-default),
+ border-color var(--sds-anim-transition-default);
+ border-bottom: 2px solid var(--Nav-navLink-border-color);
+
+ @media (hover: hover) {
+ &:hover {
+ --Nav-navLink-color: var(--sds-clr-lilac-11);
+ --Nav-navLink-border-color: var(--sds-clr-lilac-09);
+ }
+ }
+
+ &--active {
+ cursor: default;
+ --Nav-navLink-color: var(--sds-clr-lilac-11);
+ --Nav-navLink-border-color: var(--sds-clr-lilac-09);
+ }
+}
+
+.SidebarLink {
+ --SidebarLink-color: var(--sds-clr-gray-11);
+
+ font-size: pxToRem(14px);
+ line-height: pxToRem(20px);
+ font-weight: var(--sds-fw-medium);
+ color: var(--SidebarLink-color);
+ transition:
+ color var(--sds-anim-transition-default),
+ font-weight var(--sds-anim-transition-default);
+ text-decoration: none;
+ display: flex;
+ align-items: center;
+ gap: pxToRem(4px);
+
+ svg {
+ display: block;
+ width: pxToRem(16px);
+ height: pxToRem(16px);
+ stroke: var(--SidebarLink-color);
+ }
+
+ @media (hover: hover) {
+ &:hover {
+ --SidebarLink-color: var(--sds-clr-lilac-11);
+ font-weight: var(--sds-fw-semi-bold);
+ }
+ }
+
+ &--active {
+ --SidebarLink-color: var(--sds-clr-lilac-11);
+ cursor: default;
+ font-weight: var(--sds-fw-semi-bold);
+ }
+}
diff --git a/src/styles/utils.scss b/src/styles/utils.scss
new file mode 100644
index 00000000..9486e6b8
--- /dev/null
+++ b/src/styles/utils.scss
@@ -0,0 +1,12 @@
+@use "sass:math";
+
+// Convert px to rem
+$base-font-size: 16px;
+
+@function removePxUnit($value) {
+ @return math.div($value, $value * 0 + 1);
+}
+
+@function pxToRem($pxValue) {
+ @return #{math.div(removePxUnit($pxValue), removePxUnit($base-font-size))}rem;
+}
diff --git a/tsconfig.json b/tsconfig.json
index e59724b2..93a7f047 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "es5",
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -19,9 +23,19 @@
}
],
"paths": {
- "@/*": ["./src/*"]
+ "@/*": [
+ "./src/*"
+ ]
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ "build/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}
diff --git a/yarn.lock b/yarn.lock
index 2b02a91b..a0e5370b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -168,10 +168,10 @@
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz#9ab8f811930d7af3e3d549183a50884f9eb83f36"
integrity sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==
-"@stellar/design-system@^1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@stellar/design-system/-/design-system-1.1.2.tgz#09f27c13fef69975c6d9a214e770e419985c0b8e"
- integrity sha512-Vge1vYGE2QrGO9ASVyW/o68bK7/e7+TthS4MjaQ6KZB8F2VNEhgTsyOPfCIKs2iewim0jYetHA5PIBs//tapZQ==
+"@stellar/design-system@^2.0.0-beta.1":
+ version "2.0.0-beta.1"
+ resolved "https://registry.yarnpkg.com/@stellar/design-system/-/design-system-2.0.0-beta.1.tgz#ac4a73459f2bee5fd2b0f5839d02dccf1decd532"
+ integrity sha512-0q4FI2E7BrzyjBxGb3y2KuLVfEyqD+/jcAwDIImkwDyN25fb2pw0AXuZNPbSSU+3hE6Vt89n4lGXnBp/sPEVBw==
dependencies:
"@floating-ui/dom" "^1.5.3"
bignumber.js "^9.1.1"