-
Notifications
You must be signed in to change notification settings - Fork 214
Feature/tailwind v4 migration #3087
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
base: develop
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughThis pull request consolidates Tailwind CSS configuration from a distributed per-module approach to a centralized system. It migrates from Tailwind CSS 3.x to 4.1.18 with Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
package.json (1)
31-52: Add missing@plugindirectives for Tailwind v4 plugins in the CSS entry point.The installed plugins (
@tailwindcss/forms,@tailwindcss/typography, tailwind-scrollbar-hide) are compatible with Tailwind v4.1.18, and the PostCSS pipeline is correctly configured. However, the main CSS entry point (./src/base-tailwind.css) is missing the required@plugindirectives. In Tailwind v4's CSS-first approach, plugins must be explicitly loaded in the CSS file, not just installed as npm packages.Add the following to
./src/base-tailwind.cssafter the@import "tailwindcss/theme.css"line:`@plugin` "@tailwindcss/forms"; `@plugin` "@tailwindcss/typography"; `@plugin` "tailwind-scrollbar-hide";Without these directives, the plugins will not be available even though they are installed.
🤖 Fix all issues with AI agents
In `@includes/Admin/Dashboard/Dashboard.php`:
- Around line 647-649: The footer string assigned to $dom_element contains an
external anchor with target="_blank" and an unlocalized user-facing message;
update the anchor to include rel="noopener noreferrer" to prevent
reverse-tabnabbing and wrap the visible text portion with esc_html__() using the
'dokan-lite' text domain (keep any HTML markup intact, only localize the
user-facing sentence) so the output uses WordPress internationalization and is
secure; locate the assignment to $dom_element in Dashboard.php and apply these
changes to the string building around the rating link.
In `@src/base-tailwind.css`:
- Around line 85-95: The `@import` rules currently inside the .dokan-layout block
must be moved to the top of the stylesheet and placed before any selectors so
they are not ignored; remove the `@import` "tailwindcss/preflight.css"
layer(base), `@import` "tailwindcss/utilities.css", `@import`
'./dokan-components.css', and `@import` '@getdokan/dokan-ui/dist/dokan-ui.css'
from inside .dokan-layout and place them at the top of src/base-tailwind.css in
the intended order (preflight, utilities, dokan-components, dokan-ui) while
leaving only the CSS declarations such as border-color: var(--color-border);
inside the .dokan-layout selector.
In `@src/dokan-components.css`:
- Around line 8-99: The global reset/selectors (e.g., *, *::before, *::after,
table:not(.dataviews-view-table), ul, ol, h1..h6, a:focus, button:focus,
a:not(.dokan-btn)..., input[type="checkbox"]::before, textarea:focus, button,
[role="button"], input[type="button"] etc.) are currently unscoped and can leak
styles; scope these base rules by wrapping them under a container selector like
.dokan-layout (or :where(.dokan-layout)) so the resets only apply inside that
layout, and leave only truly global rules outside—update every selector in this
diff to be nested/prefixed with .dokan-layout (including the focus, link, form,
and button rule blocks) so the styles no longer affect unrelated UI.
In `@src/intelligence/components/DokanAI.tsx`:
- Around line 1-8: Imports in DokanAI.tsx reference non-existent `@dokan/`*
aliases (DokanAlert, DokanButton, DokanModal, DokanTooltip, useMutationObserver)
causing compile errors; fix by either adding path mappings for
"@dokan/components" -> "./src/components" and "@dokan/hooks" -> "./src/hooks" in
tsconfig.json and matching aliases in webpack.config.js, or update the imports
in DokanAI.tsx to use the existing "@src" alias (e.g., import { DokanAlert, ...
} from '@src/components' and import { useMutationObserver } from '@src/hooks');
also confirm SimpleInput and TextArea are actually exported from
`@getdokan/dokan-ui` and switch to a local export if not.
🧹 Nitpick comments (2)
src/admin/dashboard/style.scss (1)
16-18: Spacing value1.25remis numerically correct for Tailwind'stop-5utility.The conversion from
@apply top-5totop: 1.25rem !importantis accurate (Tailwind default: top-5 = 1.25rem). However, hardcoding spacing breaks design system alignment. If your project ever adopts custom spacing tokens, this value may drift. The!importantflag suggests this is an intentional specificity override—consider whether it could use a CSS custom property instead if theme customization becomes relevant.src/dokan-components.css (1)
485-503: Merge duplicate.dokan-ai-promptblocks for clarity.
The same selector is declared twice; combining avoids accidental overrides and keeps the style centralized.♻️ Proposed merge
-.dokan-dashboard header.dokan-ai-prompt { - margin: 0 0 10px 0; - border-bottom: 1px solid `#ededed`; - padding: 0 0 10px 0; - line-height: 1.25; -} -.dokan-dashboard header.dokan-ai-prompt { - display: flex; - justify-content: space-between; - align-items: center; - gap: 10px; - margin-bottom: 25px !important; -} +.dokan-dashboard header.dokan-ai-prompt { + margin: 0 0 10px 0; + border-bottom: 1px solid `#ededed`; + padding: 0 0 10px 0; + line-height: 1.25; + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + margin-bottom: 25px !important; +}
| $dom_element = '<span id="dokan-admin-switching" class="dokan-layout dokan-admin-page-body"></span><br/> | ||
| <span id="footer-thankyou">If you like <strong>Dokan</strong> please leave us a <a href="https://wordpress.org/support/plugin/dokan-lite/reviews?rate=5#new-post" target="_blank" class="wc-rating-link" aria-label="five star" data-rated="Thanks :)">★★★★★</a> rating. A huge thanks in advance!</span> | ||
| '; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find . -name "Dashboard.php" -path "*/Admin/Dashboard/*" | head -20Repository: getdokan/dokan
Length of output: 98
🏁 Script executed:
wc -l ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 102
🏁 Script executed:
sed -n '640,660p' ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 878
🏁 Script executed:
sed -n '620,650p' ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 1290
🏁 Script executed:
# Check if this string is localized anywhere or if there's a pattern of localization in this file
grep -n "esc_html__\|__(\|_e(" ./includes/Admin/Dashboard/Dashboard.php | head -20Repository: getdokan/dokan
Length of output: 1151
🏁 Script executed:
# Check if there are other instances of target="_blank" in the codebase without rel attribute
rg 'target="_blank"' --type php -A 1 -B 1 | head -50Repository: getdokan/dokan
Length of output: 5269
🏁 Script executed:
# Check if the string in question uses proper escaping functions
sed -n '645,655p' ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 593
🏁 Script executed:
# Check how the $dom_element is returned/output
sed -n '645,660p' ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 679
🏁 Script executed:
# Check the function signature and how the return value is used
sed -n '627,655p' ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 1103
🏁 Script executed:
# Check how this function is hooked/used
grep -n "add_switching_container" ./includes/Admin/Dashboard/Dashboard.phpRepository: getdokan/dokan
Length of output: 200
🏁 Script executed:
# Check the WordPress security concern about reverse tabnabbing - verify if this is a real concern
# by looking at WordPress documentation patterns
grep -r "rel=\"noopener noreferrer\"" ./includes --include="*.php" | head -10Repository: getdokan/dokan
Length of output: 901
🏁 Script executed:
# Verify this is an external link to wordpress.org and check if localization pattern is consistent
# Look at other admin footer related strings in the file
grep -n "footer\|admin_footer" ./includes/Admin/Dashboard/Dashboard.php -iRepository: getdokan/dokan
Length of output: 809
Add rel="noopener noreferrer" for the external rating link and localize the user-facing string.
target="_blank" without rel enables reverse-tabnabbing on external pages. Additionally, the footer text should be localized using esc_html__() with the 'dokan-lite' text domain for consistency with the plugin's localization pattern.
Proposed fix
- <span id="footer-thankyou">If you like <strong>Dokan</strong> please leave us a <a href="https://wordpress.org/support/plugin/dokan-lite/reviews?rate=5#new-post" target="_blank" class="wc-rating-link" aria-label="five star" data-rated="Thanks :)">★★★★★</a> rating. A huge thanks in advance!</span>
+ <span id="footer-thankyou"><?php esc_html_e( 'If you like ', 'dokan-lite' ); ?><strong>Dokan</strong><?php esc_html_e( ' please leave us a ', 'dokan-lite' ); ?><a href="https://wordpress.org/support/plugin/dokan-lite/reviews?rate=5#new-post" target="_blank" rel="noopener noreferrer" class="wc-rating-link" aria-label="five star" data-rated="Thanks :)">★★★★★</a><?php esc_html_e( ' rating. A huge thanks in advance!', 'dokan-lite' ); ?></span>🤖 Prompt for AI Agents
In `@includes/Admin/Dashboard/Dashboard.php` around lines 647 - 649, The footer
string assigned to $dom_element contains an external anchor with target="_blank"
and an unlocalized user-facing message; update the anchor to include
rel="noopener noreferrer" to prevent reverse-tabnabbing and wrap the visible
text portion with esc_html__() using the 'dokan-lite' text domain (keep any HTML
markup intact, only localize the user-facing sentence) so the output uses
WordPress internationalization and is secure; locate the assignment to
$dom_element in Dashboard.php and apply these changes to the string building
around the rating link.
| .dokan-layout { | ||
| @import "tailwindcss/preflight.css" layer(base); | ||
| @import "tailwindcss/utilities.css"; | ||
|
|
||
| /* Import custom component styles */ | ||
| @import './dokan-components.css'; | ||
|
|
||
| border-color: var(--color-border); | ||
|
|
||
| } | ||
| @import '@getdokan/dokan-ui/dist/dokan-ui.css'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the complete src/base-tailwind.css file to understand the context
wc -l src/base-tailwind.cssRepository: getdokan/dokan
Length of output: 172
🏁 Script executed:
# Read the file to see the actual import structure and context around lines 85-95
cat -n src/base-tailwind.css | head -100Repository: getdokan/dokan
Length of output: 3863
Move all @import statements outside of selector blocks to the top of the stylesheet.
@import rules cannot appear inside selectors or other blocks—they must be at the stylesheet root. Lines 86-90 place imports inside the .dokan-layout selector block, causing them to be ignored by browsers. Additionally, the import at line 95 should appear before style rules to ensure proper style layering.
🐛 Proposed fix
`@layer` theme, base, components, utilities;
`@import` "tailwindcss/theme.css" layer(theme);
+@import "tailwindcss/preflight.css" layer(base);
+@import "tailwindcss/utilities.css";
+@import './dokan-components.css';
+@import '@getdokan/dokan-ui/dist/dokan-ui.css';
/* ============================================
Tailwind v4 Theme Configuration
...
`@layer` base {
...
}
.dokan-layout {
- `@import` "tailwindcss/preflight.css" layer(base);
- `@import` "tailwindcss/utilities.css";
-
- /* Import custom component styles */
- `@import` './dokan-components.css';
-
border-color: var(--color-border);
}
-@import '@getdokan/dokan-ui/dist/dokan-ui.css';🧰 Tools
🪛 Biome (2.1.2)
[error] 95-95: This @import is in the wrong position.
Any @import rules must precede all other valid at-rules and style rules in a stylesheet (ignoring @charset and @layer), or else the @import rule is invalid.
Consider moving import position.
(lint/correctness/noInvalidPositionAtImportRule)
🤖 Prompt for AI Agents
In `@src/base-tailwind.css` around lines 85 - 95, The `@import` rules currently
inside the .dokan-layout block must be moved to the top of the stylesheet and
placed before any selectors so they are not ignored; remove the `@import`
"tailwindcss/preflight.css" layer(base), `@import` "tailwindcss/utilities.css",
`@import` './dokan-components.css', and `@import`
'@getdokan/dokan-ui/dist/dokan-ui.css' from inside .dokan-layout and place them
at the top of src/base-tailwind.css in the intended order (preflight, utilities,
dokan-components, dokan-ui) while leaving only the CSS declarations such as
border-color: var(--color-border); inside the .dokan-layout selector.
| *, | ||
| *::before, | ||
| *::after { | ||
| border-color: var(--color-border); | ||
| } | ||
|
|
||
| /* ========== Resets ========== */ | ||
|
|
||
| /* Table Reset */ | ||
| table:not(.dataviews-view-table), | ||
| table:not(.dataviews-view-table) th, | ||
| table:not(.dataviews-view-table) td { | ||
| margin: 0; | ||
| padding: 0; | ||
| border: 0; | ||
| border-spacing: 0; | ||
| border-collapse: collapse; | ||
| font-size: inherit; | ||
| font-weight: inherit; | ||
| text-align: inherit; | ||
| vertical-align: inherit; | ||
| box-sizing: border-box; | ||
| } | ||
|
|
||
| /* List Reset */ | ||
| ul, ol { | ||
| list-style: none; | ||
| margin: 0; | ||
| padding: 0; | ||
| } | ||
|
|
||
| li { | ||
| margin: 0; | ||
| list-style: none; | ||
| padding: 0; | ||
| } | ||
|
|
||
| /* Headings Reset */ | ||
| h1, h2, h3, h4, h5, h6 { | ||
| padding: 0; | ||
| margin: 0; | ||
| } | ||
|
|
||
| /* ========== Focus States ========== */ | ||
| a:focus, | ||
| button:focus, | ||
| textarea:focus, | ||
| input:focus { | ||
| &:not([role="switch"], [role="combobox"]) { | ||
| outline-color: var(--color-primary); | ||
| } | ||
| } | ||
|
|
||
| /* ========== Link Styles ========== */ | ||
| a:not(.dokan-btn):not([class*="dokan-btn-"]):not(.skip-color-module) { | ||
| color: var(--color-primary); | ||
| transition: color 0.2s; | ||
|
|
||
| &:hover, | ||
| &:focus { | ||
| color: var(--color-primary-dark); | ||
| } | ||
| } | ||
|
|
||
| /* ========== Form Elements ========== */ | ||
| input[type="checkbox"]::before { | ||
| content: "" !important; | ||
| } | ||
|
|
||
| textarea:focus, | ||
| input[type="text"]:focus, | ||
| input[type="number"]:focus { | ||
| outline-offset: 0; | ||
| } | ||
|
|
||
| /* ========== Global Button Cursor Styles ========== */ | ||
| button, | ||
| [role="button"], | ||
| input[type="button"], | ||
| input[type="submit"], | ||
| input[type="reset"] { | ||
| cursor: pointer; | ||
|
|
||
| &:hover:not(:disabled) { | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| &:disabled, | ||
| &[aria-disabled="true"] { | ||
| cursor: not-allowed; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scope the resets to .dokan-layout to prevent bleed‑through.
The header says these styles are scoped, but selectors like *, table, ul, a, and button are global. If this bundle loads broadly, it can override unrelated admin/UI styling. Please wrap these base rules inside .dokan-layout (or :where(.dokan-layout)), and keep only the truly global rules outside.
✅ Example wrapper (apply the same pattern to the rest of the base rules)
-*, *::before, *::after {
- border-color: var(--color-border);
-}
+ .dokan-layout {
+ *,
+ *::before,
+ *::after {
+ border-color: var(--color-border);
+ }
+
+ table:not(.dataviews-view-table),
+ table:not(.dataviews-view-table) th,
+ table:not(.dataviews-view-table) td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ border-spacing: 0;
+ border-collapse: collapse;
+ font-size: inherit;
+ font-weight: inherit;
+ text-align: inherit;
+ vertical-align: inherit;
+ box-sizing: border-box;
+ }
+
+ /* ...wrap the rest of the scoped rules here... */
+ }🤖 Prompt for AI Agents
In `@src/dokan-components.css` around lines 8 - 99, The global reset/selectors
(e.g., *, *::before, *::after, table:not(.dataviews-view-table), ul, ol, h1..h6,
a:focus, button:focus, a:not(.dokan-btn)..., input[type="checkbox"]::before,
textarea:focus, button, [role="button"], input[type="button"] etc.) are
currently unscoped and can leak styles; scope these base rules by wrapping them
under a container selector like .dokan-layout (or :where(.dokan-layout)) so the
resets only apply inside that layout, and leave only truly global rules
outside—update every selector in this diff to be nested/prefixed with
.dokan-layout (including the focus, link, form, and button rule blocks) so the
styles no longer affect unrelated UI.
| import { | ||
| DokanAlert, | ||
| DokanButton, | ||
| DokanModal, | ||
| DokanTooltip as Tooltip, | ||
| } from '@dokan/components'; | ||
| import { useMutationObserver } from '@dokan/hooks'; | ||
| import { SimpleInput, TextArea } from '@getdokan/dokan-ui'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Check if `@dokan` and `@getdokan` are local packages or external
find . -name "package.json" -type f | head -20
# Look for `@dokan` packages in the repo structure
fd -t d "@dokan" 2>/dev/null
# Look for `@getdokan` packages
fd -t d "@getdokan" 2>/dev/null
# Check for node_modules structure
ls -la node_modules/@dokan 2>/dev/null | head -20
ls -la node_modules/@getdokan 2>/dev/null | head -20Repository: getdokan/dokan
Length of output: 96
🏁 Script executed:
# Search for any barrel exports or type definitions for these packages
find . -path ./node_modules -prune -o -type f \( -name "index.ts" -o -name "index.tsx" -o -name "index.d.ts" \) -print | xargs grep -l "DokanAlert\|DokanButton\|DokanModal\|DokanTooltip\|useMutationObserver\|SimpleInput\|TextArea" 2>/dev/null | grep -v node_modulesRepository: getdokan/dokan
Length of output: 538
🏁 Script executed:
# Check workspace structure or monorepo setup
cat package.json | grep -A 20 "workspaces\|@dokan\|@getdokan" 2>/dev/nullRepository: getdokan/dokan
Length of output: 850
🏁 Script executed:
# Check tsconfig for path mappings
cat tsconfig.json 2>/dev/null | grep -A 20 "paths\|compilerOptions" | head -40Repository: getdokan/dokan
Length of output: 1105
🏁 Script executed:
# Check local exports
cat -n ./src/components/index.tsxRepository: getdokan/dokan
Length of output: 2860
🏁 Script executed:
# Check hooks exports
cat -n ./src/hooks/index.tsxRepository: getdokan/dokan
Length of output: 560
🏁 Script executed:
# Verify if `@dokan` is defined as a path alias or package
rg "@dokan" tsconfig.json jsconfig.json package.json 2>/dev/nullRepository: getdokan/dokan
Length of output: 40
🏁 Script executed:
# Check the specific imports used in DokanAI.tsx to see their actual resolution
rg "from '@dokan|from '@getdokan" src/intelligence/components/DokanAI.tsx -A 2 -B 2Repository: getdokan/dokan
Length of output: 338
🏁 Script executed:
# Check webpack.config.js for alias configuration
cat webpack.config.js 2>/dev/null | grep -A 30 "alias\|resolve" | head -50Repository: getdokan/dokan
Length of output: 1896
🏁 Script executed:
# Check if `@dokan` packages are somehow defined elsewhere
cat package.json | grep -i "@dokan\|@getdokan"Repository: getdokan/dokan
Length of output: 124
@dokan/components and @dokan/hooks aliases are not configured.
These imports will fail at compile time. Neither tsconfig.json nor webpack.config.js define path mappings or aliases for @dokan/*. The symbols (DokanAlert, DokanButton, DokanModal, DokanTooltip, useMutationObserver) do exist in the local codebase (./src/components/index.tsx and ./src/hooks/index.tsx), but the import paths are broken. Either add the missing @dokan/components and @dokan/hooks aliases to both tsconfig.json and webpack.config.js, or update imports to use the @src alias (e.g., from '@src/components', from '@src/hooks').
Additionally, verify that SimpleInput and TextArea are exported from the external @getdokan/dokan-ui package.
🤖 Prompt for AI Agents
In `@src/intelligence/components/DokanAI.tsx` around lines 1 - 8, Imports in
DokanAI.tsx reference non-existent `@dokan/`* aliases (DokanAlert, DokanButton,
DokanModal, DokanTooltip, useMutationObserver) causing compile errors; fix by
either adding path mappings for "@dokan/components" -> "./src/components" and
"@dokan/hooks" -> "./src/hooks" in tsconfig.json and matching aliases in
webpack.config.js, or update the imports in DokanAI.tsx to use the existing
"@src" alias (e.g., import { DokanAlert, ... } from '@src/components' and import
{ useMutationObserver } from '@src/hooks'); also confirm SimpleInput and
TextArea are actually exported from `@getdokan/dokan-ui` and switch to a local
export if not.
All Submissions:
Changes proposed in this Pull Request:
Related Pull Request(s)
Closes
How to test the changes in this Pull Request:
Changelog entry
Title
Detailed Description of the pull request. What was previous behaviour
and what will be changed in this PR.
Before Changes
Describe the issue before changes with screenshots(s).
After Changes
Describe the issue after changes with screenshot(s).
Feature Video (optional)
Link of detailed video if this PR is for a feature.
PR Self Review Checklist:
FOR PR REVIEWER ONLY:
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.