Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: implement Premium features page using shadcn/ui and Tailwind #15094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Nov 6, 2024

Conversation

jaaydenh
Copy link
Contributor

@jaaydenh jaaydenh commented Oct 15, 2024

resolves coder/internal#176

This is a proof of concept to showcase the use of Tailwind + shadcn/ui. The goal here was to implement a lower complexity page to reduce the initial risk and highlight the specific global changes needed.

Changes:

Screenshot 2024-11-01 at 12 46 03 PM Screenshot 2024-11-01 at 12 45 36 PM

@jaaydenh jaaydenh self-assigned this Oct 15, 2024
@jaaydenh jaaydenh changed the title Tailwind Experiment feat: run tailwind experiment Oct 15, 2024
@jaaydenh jaaydenh force-pushed the tailwind-experiment branch from a8f0643 to 45daf0a Compare October 16, 2024 17:42
@github-actions github-actions bot added the stale This issue is like stale bread. label Oct 24, 2024
@github-actions github-actions bot closed this Oct 27, 2024
@jaaydenh jaaydenh reopened this Oct 28, 2024
@github-actions github-actions bot removed the stale This issue is like stale bread. label Oct 29, 2024
@jaaydenh jaaydenh force-pushed the tailwind-experiment branch 2 times, most recently from c020034 to 18da110 Compare November 1, 2024 16:29
@jaaydenh jaaydenh changed the title feat: run tailwind experiment feat: Implement Premium features page using shadcn/ui and Tailwind Nov 1, 2024
@jaaydenh jaaydenh force-pushed the tailwind-experiment branch from 18da110 to f08bee2 Compare November 1, 2024 16:58
@jaaydenh jaaydenh requested a review from Parkreiner November 1, 2024 16:59
@jaaydenh jaaydenh changed the title feat: Implement Premium features page using shadcn/ui and Tailwind feat: implement Premium features page using shadcn/ui and Tailwind Nov 1, 2024
@jaaydenh jaaydenh requested a review from aslilac November 1, 2024 19:44
@aslilac
Copy link
Member

aslilac commented Nov 1, 2024

what's the difference between the two screen shots? I recognize the first design from figma, but I don't understand the second screenshot

Comment on lines 14 to 18
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeling these are all very wrong

Copy link
Contributor Author

@jaaydenh jaaydenh Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default generation by shadcn when running pnpm dlx shadcn@latest init . components.json is only used when using the shadcn cli. I haven't really decided what to do about this yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, one question is if we should keep shadcn components in a separate folder currently its ui to make it clear which ones they are? or just place them in components with everything else.

@@ -49,6 +50,8 @@
"@mui/system": "5.16.7",
"@mui/utils": "5.16.6",
"@mui/x-tree-view": "7.18.0",
"@radix-ui/react-icons": "1.3.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're using radix icons and lucide?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So both were added when doing the shadcn installation, lucide is used by the default style and radix icons is used by the new-york style. Since we are going to use neither style, I need to update this for the icon library we are using going forward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it looks like Christin is using Lucide icons in Figma, I am going to update this to use those.

Comment on lines +1 to +6
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought tailwind was moving away from postcss. am I misremembering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

postcss seems to required when using vite

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the have their own custom parser, so they're slowly moving away from PostCSS. But they're still supporting it for now

@@ -92,6 +92,7 @@ export default defineConfig({
testHelpers: path.resolve(__dirname, "./src/testHelpers"),
theme: path.resolve(__dirname, "./src/theme"),
utils: path.resolve(__dirname, "./src/utils"),
"@": path.resolve(__dirname, "./src"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we already have aliases for all of the top level folders, let's not add multiple ways to do things pls

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a left over piece from the shadcn installation

"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules/", "_jest"],
"types": ["@emotion/react", "@testing-library/jest-dom", "jest", "node"]
"compilerOptions": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk how this wasn't tabs already, but thank you!

Template Permissions
</span>
<br />
<span className=" font-medium">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<span className=" font-medium">
<span className="font-medium">

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we get Tailwind class sorting figured out, this shouldn't happen anymore.

Comment on lines +8 to +10
export const PremiumPageView: FC<PremiumPageViewProps> = ({ isEnterprise }) => {
return isEnterprise ? <EnterpriseVersion /> : <OSSVersion />;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh weird. I don't remember seeing this in the designs. did sales ask for this or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, It was requested and the designs have been updated since then.

@@ -55,6 +55,17 @@ export const ThemeProvider: FC<PropsWithChildren> = ({ children }) => {
// The janky casting here is find because of the much more type safe fallback
// We need to support `themePreference` being wrong anyway because the database
// value could be anything, like an empty string.

useEffect(() => {
const root = window.document.documentElement;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const root = window.document.documentElement;
const root = document.documentElement;

import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react";

import { cn } from "@/lib/utils";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're gonna wanna change this path to fit in with what we've already got. maybe modules/classes.ts or utils/classes.ts? I'd lean towards modules as I don't really like the name "utils", everything is a util but nothing should just be a util, y'know?

site/src/App.tsx Outdated
{showDevtools && <ReactQueryDevtools initialIsOpen={showDevtools} />}
</QueryClientProvider>
</HelmetProvider>
<CacheProvider value={cache}>
Copy link
Member

@aslilac aslilac Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this provider actually go inside ThemeProvider instead, since it's already doing emotion related stuff?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, seems like that is fine.

@jaaydenh
Copy link
Contributor Author

jaaydenh commented Nov 1, 2024

what's the difference between the two screen shots? I recognize the first design from figma, but I don't understand the second screenshot

The first is for Enterprise users, the second for OSS users.

@jaaydenh jaaydenh marked this pull request as ready for review November 1, 2024 21:10
Copy link
Member

@Parkreiner Parkreiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't sure if you were looking for feedback, or want to treat this as a "100% real" PR, and need approval. Approving just in case, because I don't see anything egregious

I left a comment about one pattern that I'm not a huge fan of, but in practice, it might not be a huge deal. Mainly worried about dev experience, and making sure the right props are getting applied to the right elements

Comment on lines +1 to +6
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the have their own custom parser, so they're slowly moving away from PostCSS. But they're still supporting it for now

);
},
);
Button.displayName = "Button";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaaydenh @aslilac Should we make a rule to add explicit displayName properties to each component? I know that these just help with debugging, but it would feel weird to do it for some components, but not others

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a good idea, although if its required we will have to add it to all existing components. shadcn components always have the displayName

Comment on lines 61 to 73
useEffect(() => {
const root = document.documentElement;
root.classList.remove("light", "dark");
if (themePreference === "auto") {
root.classList.add(preferredColorScheme);
} else {
root.classList.add(themePreference);
}
}, [themePreference, preferredColorScheme]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not as familiar with the logic for the theme. Is there a reason we're not attaching the remove functionality to a cleanup function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats a good idea to add the cleanup function. I originally only wanted to add or remove the dark class as thats all that needed and not touch the light class but I think this code is a bit simpler considering preferredColorScheme

Comment on lines +82 to +90
const cache = createCache({
key: "css",
prepend: true,
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a comment on why we're defining a custom cache override? I'm guessing this is to make Emotion and Tailwind play nicely with each other, but I'm not 100% sure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to allow using Tailwind on MUI components as described here: https://mui.com/material-ui/integrations/interoperability/#tailwind-css

This is actually not needed if never use Tailwind on MUI components and only use Tailwind with new components. I was adding it here just in case it is useful but actually maybe its better we don't add this. Any opinions either way?

--surface-error: #450a0a;
--border-default: #e4e4e7;
--border-error: #ef4444;
--radius: 0.5rem;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making sure I'm understanding this correctly: does this bind the border radius value to the root em for the browser?

If so, do we want to do that? If the user ever increases or decreases their default font size, that would cause the borders to increase/decrease roundness and potentially look wonky, right?

Copy link
Contributor Author

@jaaydenh jaaydenh Nov 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--radius is used in the tailwind config here,

borderRadius: {
   lg: "var(--radius)",
   md: "calc(var(--radius) - 2px)",
   sm: "calc(var(--radius) - 4px)",
},

by default Tailwind uses border-radius: 0.5rem; for rounded-lg so nothing is changing there. Changing the zoom level in the browser should by fine as well.

These were both added by the shadcn installation. I was keeping this for now until we know exactly why shadcn is adding this override to Tailwind for md and sm.


const EnterpriseVersion: FC = () => {
return (
<div className="max-w-4xl">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be max-w-prose?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This max width is used to set the position of the button. using max-w-prose doesn't push the button far enough to the right.

Comment on lines 24 to 28
<Button asChild>
<a href="https://coder.com/contact/sales" className="no-underline">
Upgrade
</a>
</Button>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code might be perfectly fine, but seeing this immediately makes me a little worried. Part of the reason why I haven't liked MUI is because they've tried really hard to blur the lines of links and buttons, and the resulting props are kind of a mess, and the actual function component is weirdly megamorphic

I'd need to look into exactly how Radix's Slot component works under the hood, but I'm okay with this if the developer experience is still good, and there's no risk of "mixing metaphors" by putting button-exclusive props onto anchors

href={docs("/admin/users/organizations")}
>
<span className="flex items-center">
<h2 className="text-sm font-semibold m-0">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a need for an m-0? Seeing that makes me think that Tailwind's default reset isn't being applied correctly. Though I'm not sure if that's actually expected while we're migrating off MUI

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the tailwind config the css reset is turned off.

corePlugins: {
		preflight: false,
	},

So we are going to need to do things like this in the short-term or maybe we can find another workaround

);
};

const OSSVersion: FC = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spacing on this version seems a little off, and doesn't really line up with what's happening in the Premium version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Figma, there are really 2 separate designs for OSS/Enterprise with different spacings.

},
colors: {
content: {
primary: "var(--content-primary)",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if it might be good to define default values for the var calls, just in the off chance that a variable isn't defined

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we have potentially 2 sources of truth for the colors. I would imagine that once this setup, it would rarely change.

@Parkreiner
Copy link
Member

Parkreiner commented Nov 2, 2024

Now that I think about it, I wonder if it might be good to see if we can request copies of Refactoring UI for everyone. Tailwind is basically all the ideas in that book turned into a library, so reading through it might help make some of the ways Tailwind does things seem feel less arbitrary

"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit"
// "source.organizeImports.biome": "explicit"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: should we just remove it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aslilac Were you keeping this around for some reason?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to re-enable it after Biome pushed a couple more bug fix releases. Enabling this would mean that it'd sort imports on file save (and avoid annoying CI failures) but someone (I think Asher?) encountered a really nasty bug with it. It's been a few months though, so maybe we should enable it!

Copy link
Collaborator

@BrunoQuaresma BrunoQuaresma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks really nice!

@jaaydenh jaaydenh force-pushed the tailwind-experiment branch from cff53e6 to 0614f57 Compare November 4, 2024 17:13
Copy link

github-actions bot commented Nov 4, 2024


🚀 Deploying PR 15094 ...

@jaaydenh jaaydenh force-pushed the tailwind-experiment branch from 230244e to 87fd564 Compare November 5, 2024 14:53
@jaaydenh jaaydenh force-pushed the tailwind-experiment branch from 302ca4f to 962045c Compare November 5, 2024 23:32
Copy link

@chrifro chrifro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you adjust the text to use sentence case instead of title case? So only sentence starts and proper names are spelled with a capital letter. This applies to the text and the button. FYI, Matt agreed to the change [1]. I also updated the copy in Figma

Note: unfortunately, I the PR deployment didn't work for me so I was unable to review the UI. Atif is working on fixing that [1] 🙇‍♀️

@jaaydenh jaaydenh merged commit d4131ba into main Nov 6, 2024
30 checks passed
@jaaydenh jaaydenh deleted the tailwind-experiment branch November 6, 2024 17:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

site: Add a page describing premium features to the deployment settings
5 participants