Skip to content

Commit a63e79a

Browse files
Merge pull request #423 from pankod/feat/add-shadcn-ui
2 parents f149619 + 9efd767 commit a63e79a

237 files changed

Lines changed: 22295 additions & 60 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-template.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const buildTemplate = async () => {
3434
mui: "mui-example",
3535
no: "headless-example",
3636
tailwindcss: "headless-example",
37+
shadcn: "shadcn-example",
3738
};
3839

3940
let AUTH_PROVIDER = dataProviderMap[DATA_PROVIDER];

.github/workflows/test-local.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
appwrite,
2424
hasura,
2525
]
26-
ui_framework: [tailwindcss, antd, mui, no]
26+
ui_framework: [shadcn, tailwindcss, antd, mui, no]
2727
steps:
2828
- name: Checkout
2929
uses: actions/checkout@v3
@@ -80,7 +80,7 @@ jobs:
8080
appwrite,
8181
hasura,
8282
]
83-
ui_framework: [tailwindcss, antd, mui, no]
83+
ui_framework: [shadcn, tailwindcss, antd, mui, no]
8484
steps:
8585
- name: Checkout
8686
uses: actions/checkout@v3

.github/workflows/test-remote.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
appwrite,
2424
hasura,
2525
]
26-
ui_framework: [tailwindcss, antd, mui, no]
26+
ui_framework: [shadcn, tailwindcss, antd, mui, no]
2727
steps:
2828
- name: Checkout
2929
uses: actions/checkout@v3
@@ -81,7 +81,7 @@ jobs:
8181
appwrite,
8282
hasura,
8383
]
84-
ui_framework: [tailwindcss, antd, mui, no]
84+
ui_framework: [shadcn, tailwindcss, antd, mui, no]
8585
steps:
8686
- name: Checkout
8787
uses: actions/checkout@v3

cypress/e2e/build-test.cy.js

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,28 @@ describe("build test", () => {
4040
cy.url().should("not.contain", "http://localhost:3000");
4141
}
4242
} else {
43-
cy.contains("Sign in to your account", { timeout: 10000 }).should(
44-
"exist",
45-
);
46-
47-
cy.contains("Forgot password?").click();
43+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
44+
cy.contains("Sign in", { timeout: 10000 }).should("exist");
45+
} else {
46+
cy.contains("Sign in to your account", {
47+
timeout: 10000,
48+
}).should("exist");
49+
}
50+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
51+
cy.contains("Forgot password").click();
52+
} else {
53+
cy.contains("Forgot password?").click();
54+
}
4855

4956
cy.wait(1000);
5057

5158
cy.url().should("contain", "/forgot-password");
5259

53-
cy.contains("Sign in").click();
60+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
61+
cy.contains("Back").click();
62+
} else {
63+
cy.contains("Sign in").click();
64+
}
5465

5566
cy.wait(1000);
5667

@@ -62,7 +73,11 @@ describe("build test", () => {
6273

6374
cy.url().should("contain", "/register");
6475

65-
cy.contains("Sign up for your account").should("exist");
76+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
77+
cy.contains("Sign up").click();
78+
} else {
79+
cy.contains("Sign up for your account").should("exist");
80+
}
6681

6782
cy.contains("Sign in").click();
6883

@@ -72,12 +87,20 @@ describe("build test", () => {
7287
failOnStatusCode: false,
7388
}).wait(1000);
7489

75-
cy.url().should("be.oneOf", [
76-
"http://localhost:3000/login?to=%2Fi-dont-exist",
77-
"http://localhost:3000/login?to=/i-dont-exist",
78-
]);
90+
cy.url().should(
91+
"be.oneOf",
92+
[
93+
"http://localhost:3000/login?to=%2Fi-dont-exist",
94+
"http://localhost:3000/login?to=/i-dont-exist",
95+
],
96+
{ timeout: 10000 },
97+
);
7998

80-
cy.contains("Sign in to your account").should("exist");
99+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
100+
cy.contains("Sign in").should("exist");
101+
} else {
102+
cy.contains("Sign in to your account").should("exist");
103+
}
81104

82105
if (
83106
Cypress.env("UI_FRAMEWORK") === "no" ||
@@ -92,6 +115,16 @@ describe("build test", () => {
92115
}
93116
}
94117

118+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
119+
if (Cypress.env("DATA_PROVIDER") === "supabase") {
120+
cy.get("#email").type("info@refine.dev");
121+
cy.get("input[type='password']").type("refine-supabase");
122+
} else {
123+
cy.get("#email").type("demo@refine.dev");
124+
cy.get("input[type='password']").type("demodemo");
125+
}
126+
}
127+
95128
cy.wait(1000).get("form").submit();
96129

97130
cy.wait(1000);
@@ -100,11 +133,15 @@ describe("build test", () => {
100133
timeout: 3000,
101134
});
102135

103-
cy.contains("Sorry, the page you visited does not exist.").should(
104-
"exist",
105-
);
106-
107-
cy.contains("Back Home").click();
136+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
137+
cy.contains("Page not found.").should("exist");
138+
cy.contains("Back to homepage").click();
139+
} else {
140+
cy.contains(
141+
"Sorry, the page you visited does not exist.",
142+
).should("exist");
143+
cy.contains("Back Home").click();
144+
}
108145

109146
cy.wait(1000);
110147

@@ -122,7 +159,17 @@ describe("build test", () => {
122159
) {
123160
cy.contains("Categories").should("exist");
124161

125-
cy.contains("Logout").should("exist");
162+
if (Cypress.env("UI_FRAMEWORK") === "shadcn") {
163+
// For shadcn, logout is in a dropdown menu
164+
// First click the avatar button to open dropdown
165+
cy.get('button:has([data-slot="avatar"])').click();
166+
167+
// Then verify the logout option is visible in the dropdown
168+
cy.contains("Logout").should("exist");
169+
} else {
170+
// For other UI frameworks, logout is directly visible
171+
cy.contains("Logout").should("exist");
172+
}
126173
}
127174
}
128175
});

presets.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,19 @@ module.exports = {
112112
"headless-example": "no",
113113
},
114114
},
115+
{
116+
name: "vite-shadcn",
117+
type: "refine-vite",
118+
answers: {
119+
"ui-framework": "shadcn",
120+
"router-provider": "react-router",
121+
"data-provider": "data-provider-custom-json-rest",
122+
"auth-provider": "none",
123+
"antd-example": "no",
124+
"mui-example": "no",
125+
"headless-example": "no",
126+
"shadcn-example": "shadcn-example",
127+
},
128+
},
115129
],
116130
};

refine-nextjs/plugins/_base/extend.js

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ module.exports = {
2828
const dataProvider = answers["data-provider"];
2929
const authProvider = answers["auth-provider"];
3030
const isHeadless =
31-
uiFramework === "no" || uiFramework === "tailwindcss";
31+
uiFramework === "no" ||
32+
uiFramework === "tailwindcss" ||
33+
uiFramework === "shadcn";
3234

3335
// ## isNextAuthCheck
3436
if (
@@ -51,6 +53,18 @@ module.exports = {
5153
}
5254
// ## isAuthProviderCheck
5355

56+
// ## isCustomLoginPage
57+
if (
58+
authProvider === "auth-provider-auth0" ||
59+
authProvider === "auth-provider-google" ||
60+
authProvider === "auth-provider-keycloak" ||
61+
authProvider === "auth-provider-custom" ||
62+
uiFramework === "shadcn"
63+
) {
64+
base._app.isCustomLoginPage = true;
65+
}
66+
// ## isCustomLoginPage
67+
5468
// ## authPageProps
5569
let defaultValuePropsName = "initialValues";
5670
let defaultValues = `email: "demo@refine.dev", password: "demodemo"`;
@@ -96,9 +110,12 @@ module.exports = {
96110

97111
// ## hasRoutes
98112
if (
99-
["headless-example", "antd-example", "mui-example"].every(
100-
(item) => answers[item] === "no",
101-
)
113+
[
114+
"headless-example",
115+
"antd-example",
116+
"mui-example",
117+
"shadcn-example",
118+
].every((item) => answers[item] === "no")
102119
) {
103120
base._app.hasRoutes = false;
104121
}
@@ -135,10 +152,14 @@ module.exports = {
135152
}
136153

137154
if (isHeadless) {
138-
base._app.localImport.push(
139-
`import { Layout } from "@components/layout";`,
140-
);
141-
base._app.localImport.push(`import "@styles/global.css";`);
155+
// Only add generic layout for non-shadcn headless frameworks
156+
// shadcn handles its own Layout import in shadcn/extend.js
157+
if (uiFramework !== "shadcn") {
158+
base._app.localImport.push(
159+
`import { Layout } from "@components/layout";`,
160+
);
161+
base._app.localImport.push(`import "@styles/global.css";`);
162+
}
142163
}
143164

144165
// this impementation required for getting default ColorModeContextProvider's theme from cookie

refine-nextjs/plugins/auth-provider-auth0/src/app/login/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export default function Login() {
9696
);
9797
<%_ } _%>
9898

99-
<%_ if (answers["ui-framework"] === "no" || answers["ui-framework"] === "tailwindcss") { _%>
99+
<%_ if (answers["ui-framework"] === "no" || answers["ui-framework"] === "tailwindcss" || answers["ui-framework"] === "shadcn") { _%>
100100
return(
101101
<div
102102
style={{

refine-nextjs/plugins/auth-provider-custom/src/app/forgot-password/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
<%_ if (answers["ui-framework"] === "shadcn") { _%>
2+
import { ForgotPasswordForm } from "@/components/refine-ui/form/forgot-password-form";
3+
<%_ } else { _%>
14
import { AuthPage } from "@components/auth-page";
5+
<%_ } _%>
26
import { authProviderServer } from "@providers/auth-provider/auth-provider.server";
37
import { redirect } from "next/navigation";
48

@@ -9,7 +13,11 @@ export default async function ForgotPassword() {
913
redirect(data?.redirectTo || "/");
1014
}
1115

16+
<%_ if (answers["ui-framework"] === "shadcn") { _%>
17+
return <ForgotPasswordForm />;
18+
<%_ } else { _%>
1219
return <AuthPage type="forgotPassword" />;
20+
<%_ } _%>
1321
}
1422

1523
async function getData() {

refine-nextjs/plugins/auth-provider-custom/src/app/login/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
<%_ if (answers["ui-framework"] === "shadcn") { _%>
2+
import { SignInForm } from "@/components/refine-ui/form/sign-in-form";
3+
<%_ } else { _%>
14
import { AuthPage } from "@components/auth-page";
5+
<%_ } _%>
26
import { authProviderServer } from "@providers/auth-provider/auth-provider.server";
37
import { redirect } from "next/navigation";
48

@@ -9,7 +13,11 @@ export default async function Login() {
913
redirect(data?.redirectTo || "/");
1014
}
1115

16+
<%_ if (answers["ui-framework"] === "shadcn") { _%>
17+
return <SignInForm />;
18+
<%_ } else { _%>
1219
return <AuthPage type="login" />;
20+
<%_ } _%>
1321
}
1422

1523
async function getData() {

refine-nextjs/plugins/auth-provider-custom/src/app/register/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
<%_ if (answers["ui-framework"] === "shadcn") { _%>
2+
import { SignUpForm } from "@/components/refine-ui/form/sign-up-form";
3+
<%_ } else { _%>
14
import { AuthPage } from "@components/auth-page";
5+
<%_ } _%>
26
import { authProviderServer } from "@providers/auth-provider/auth-provider.server";
37
import { redirect } from "next/navigation";
48

@@ -9,7 +13,11 @@ export default async function Register() {
913
redirect(data?.redirectTo || "/");
1014
}
1115

16+
<%_ if (answers["ui-framework"] === "shadcn") { _%>
17+
return <SignUpForm />;
18+
<%_ } else { _%>
1219
return <AuthPage type="register" />;
20+
<%_ } _%>
1321
}
1422

1523
async function getData() {

0 commit comments

Comments
 (0)