chore(tailwind-css): migrate to css first (#35754)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
yyh
2026-05-06 04:28:11 +00:00
committed by GitHub
co-authored by autofix-ci[bot] copilot-swe-agent[bot]
parent 70eb98d6c5
commit b2dacf0718
38 changed files with 1190 additions and 1305 deletions
-1
View File
@@ -6,7 +6,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { I18nClientProvider as I18N } from '../app/components/provider/i18n'
import commonEnUS from '../i18n/en-US/common.json'
import '../app/styles/globals.css'
import '../app/styles/markdown.css'
import './storybook.css'
+13
View File
@@ -1,3 +1,16 @@
@import '../app/styles/tailwind-core.css';
@source '../app';
@source '../context';
@source '../hooks';
@source '.';
@source '../../packages/dify-ui/src';
@source '../node_modules/streamdown/dist';
@source '../node_modules/@streamdown/math/dist';
@source not '../**/*.{spec,test}.{js,ts,jsx,tsx}';
@source not '../../packages/dify-ui/src/**/*.{spec,test}.{ts,tsx}';
@source not '../../packages/dify-ui/src/**/*.stories.{ts,tsx}';
html,
body {
max-width: unset;
@@ -255,7 +255,6 @@ const TestThemeProvider = ({ children }: { children: React.ReactNode }) => (
defaultTheme="system"
enableSystem
disableTransitionOnChange
enableColorScheme={false}
>
{children}
</ThemeProvider>
@@ -15,9 +15,9 @@ import type {
import { cn } from '@langgenius/dify-ui/cn'
import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectItemText, SelectTrigger } from '@langgenius/dify-ui/select'
import { useCallback, useState } from 'react'
import { Infotip } from '@/app/components/base/infotip'
import Radio from '@/app/components/base/radio'
import RadioE from '@/app/components/base/radio/ui'
import Tooltip from '@/app/components/base/tooltip'
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector'
import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector'
@@ -28,6 +28,23 @@ import { FormTypeEnum } from '../declarations'
import { useLanguage } from '../hooks'
import Input from './Input'
const radioGridColumnsClassNames: Record<number, string> = {
1: 'grid-cols-1',
2: 'grid-cols-2',
3: 'grid-cols-3',
4: 'grid-cols-4',
5: 'grid-cols-5',
6: 'grid-cols-6',
7: 'grid-cols-7',
8: 'grid-cols-8',
9: 'grid-cols-9',
10: 'grid-cols-10',
11: 'grid-cols-11',
12: 'grid-cols-12',
}
type ModelSelectorValue = Record<string, unknown>
type FormProps<
CustomFormSchema extends Omit<CredentialFormSchema, 'type'> & { type: string } = never,
> = {
@@ -100,7 +117,7 @@ function Form<
fieldMoreInfo,
}
const handleFormChange = (key: string, val: string | boolean) => {
const handleFormChange = (key: string, val: FormValue[string]) => {
if (isEditMode && (key === '__model_type' || key === '__model_name'))
return
@@ -115,7 +132,7 @@ function Form<
onChange({ ...value, [key]: val, ...shouldClearVariable })
}
const handleModelChanged = useCallback((key: string, model: any) => {
const handleModelChanged = useCallback((key: string, model: ModelSelectorValue) => {
const newValue = {
...value[key],
...model,
@@ -125,17 +142,16 @@ function Form<
}, [onChange, value])
const renderField = (formSchema: CredentialFormSchema | CustomFormSchema) => {
const tooltip = formSchema.tooltip
const tooltipContent = (tooltip && (
<Tooltip
popupContent={(
<div className="w-[200px]">
{tooltip[language] || tooltip.en_US}
</div>
)}
triggerClassName="ml-1 w-4 h-4"
asChild={false}
/>
const infotip = formSchema.tooltip
const infotipText = infotip?.[language] || infotip?.en_US
const infotipContent = (infotipText && (
<Infotip
aria-label={infotipText}
className="ml-1"
popupClassName="w-[200px] max-w-[200px]"
>
{infotipText}
</Infotip>
))
if (override) {
const [overrideTypes, overrideRender] = override
@@ -166,7 +182,7 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<Input
className={cn(inputClassName, `${disabled && 'cursor-not-allowed opacity-60'}`)}
@@ -201,6 +217,7 @@ function Form<
return null
const disabled = isEditMode && (variable === '__model_type' || variable === '__model_name')
const gridColumnsClassName = radioGridColumnsClassNames[options.length] ?? 'grid-cols-1'
return (
<div key={variable} className={cn(itemClassName, 'py-3')}>
@@ -209,10 +226,9 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
{/* eslint-disable-next-line tailwindcss/no-unknown-classes */}
<div className={cn('grid gap-3', `grid-cols-${options?.length}`)}>
<div className={cn('grid gap-3', gridColumnsClassName)}>
{options.filter((option) => {
if (option.show_on.length)
return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value)
@@ -272,7 +288,7 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<Select
disabled={readonly}
@@ -320,7 +336,7 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<Radio.Group
className="flex items-center"
@@ -350,7 +366,7 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<ModelParameterModal
popupClassName="w-[387px]!"
@@ -382,7 +398,7 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<ToolSelector
scope={scope}
@@ -392,8 +408,8 @@ function Form<
disabled={readonly}
value={value[variable]}
// selectedTools={value[variable] ? [value[variable]] : []}
onSelect={item => handleFormChange(variable, item as any)}
onDelete={() => handleFormChange(variable, null as any)}
onSelect={item => handleFormChange(variable, item)}
onDelete={() => handleFormChange(variable, null)}
/>
{fieldMoreInfo?.(formSchema)}
{validating && changeKey === variable && <ValidatingTip />}
@@ -405,7 +421,7 @@ function Form<
const {
variable,
label,
tooltip,
tooltip: infotip,
required,
scope,
} = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput)
@@ -420,9 +436,9 @@ function Form<
scope={scope}
label={label[language] || label.en_US}
required={required}
tooltip={tooltip?.[language] || tooltip?.en_US}
tooltip={infotip?.[language] || infotip?.en_US}
value={value[variable] || []}
onChange={item => handleFormChange(variable, item as any)}
onChange={item => handleFormChange(variable, item)}
supportCollapse
/>
{fieldMoreInfo?.(formSchema)}
@@ -446,13 +462,13 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<AppSelector
disabled={readonly}
scope={scope}
value={value[variable]}
onSelect={item => handleFormChange(variable, { ...item, type: FormTypeEnum.appSelector } as any)}
onSelect={item => handleFormChange(variable, { ...item, type: FormTypeEnum.appSelector })}
/>
{fieldMoreInfo?.(formSchema)}
{validating && changeKey === variable && <ValidatingTip />}
@@ -475,7 +491,7 @@ function Form<
{required && (
<span className="ml-1 text-red-500">*</span>
)}
{tooltipContent}
{infotipContent}
</div>
<VarReferencePicker
zIndex={1001}
@@ -483,7 +499,7 @@ function Form<
isShowNodeName
nodeId={nodeId || ''}
value={value[variable] || []}
onChange={item => handleFormChange(variable, item as any)}
onChange={item => handleFormChange(variable, item)}
filterVar={(varPayload) => {
if (!scope)
return true
@@ -1235,6 +1235,10 @@ describe('Form', () => {
expect(screen.getByText('Region'))!.toBeInTheDocument()
expect(screen.getByText('Model'))!.toBeInTheDocument()
expect(screen.getByText('Agree'))!.toBeInTheDocument()
expect(screen.getByLabelText('Enter your API key here'))!.toBeInTheDocument()
expect(screen.getByLabelText('Select region'))!.toBeInTheDocument()
expect(screen.getByLabelText('Choose model'))!.toBeInTheDocument()
expect(screen.getByLabelText('Agree tooltip'))!.toBeInTheDocument()
})
it('should render required asterisk for radio, select, checkbox, and other field types', () => {
@@ -651,7 +651,6 @@ describe('Workflow edge event wiring', () => {
await waitFor(() => {
expect(toastInfoMock).toHaveBeenCalledWith(
'workflow.versionHistory.action.restoreInProgress:{"userName":"Alice","versionName":"Version One"}',
{ timeout: 3000 },
)
})
})
+1 -1
View File
@@ -283,7 +283,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
ns: 'workflow',
userName: data.initiatorName,
versionName: data.versionName || data.versionId,
}), { timeout: 3000 })
}))
})
}, [t])
@@ -226,6 +226,11 @@ describe('node actions menu details', () => {
const user = userEvent.setup()
renderDropdownContent()
const deleteMenuItem = screen.getByText('common.operation.delete').closest('[role="menuitem"]')
expect(deleteMenuItem).toHaveAttribute('data-variant', 'default')
expect(deleteMenuItem).toHaveClass('text-text-secondary')
expect(deleteMenuItem).toHaveClass('data-highlighted:text-text-destructive')
await user.click(screen.getByText('workflow.panel.runThisStep'))
await user.click(screen.getByText('workflow.common.copy'))
await user.click(screen.getByText('workflow.common.duplicate'))
@@ -8,6 +8,7 @@ import {
import { useTranslation } from 'react-i18next'
import { ChangeBlockMenuTrigger } from './change-block-menu-trigger'
import {
NODE_ACTIONS_MENU_DELETE_ITEM_CLASS_NAME,
NODE_ACTIONS_MENU_ITEM_WITH_SHORTCUT_CLASS_NAME,
NodeActionsMenuAbout,
NodeActionsMenuItemContent,
@@ -64,8 +65,7 @@ export function NodeActionsContextMenuContent(props: NodeActionsMenuProps) {
{hasDeleteGroup && (
<ContextMenuGroup>
<ContextMenuItem
variant="destructive"
className={NODE_ACTIONS_MENU_ITEM_WITH_SHORTCUT_CLASS_NAME}
className={NODE_ACTIONS_MENU_DELETE_ITEM_CLASS_NAME}
onClick={model.handleDelete}
>
<NodeActionsMenuItemContent shortcut="workflow.delete">
@@ -8,6 +8,7 @@ import {
import { useTranslation } from 'react-i18next'
import { ChangeBlockMenuTrigger } from './change-block-menu-trigger'
import {
NODE_ACTIONS_MENU_DELETE_ITEM_CLASS_NAME,
NODE_ACTIONS_MENU_ITEM_WITH_SHORTCUT_CLASS_NAME,
NodeActionsMenuAbout,
NodeActionsMenuItemContent,
@@ -64,8 +65,7 @@ export function NodeActionsDropdownContent(props: NodeActionsMenuProps) {
{hasDeleteGroup && (
<DropdownMenuGroup>
<DropdownMenuItem
variant="destructive"
className={NODE_ACTIONS_MENU_ITEM_WITH_SHORTCUT_CLASS_NAME}
className={NODE_ACTIONS_MENU_DELETE_ITEM_CLASS_NAME}
onClick={model.handleDelete}
>
<NodeActionsMenuItemContent shortcut="workflow.delete">
@@ -5,6 +5,7 @@ import { ShortcutKbd } from '@/app/components/workflow/shortcuts/shortcut-kbd'
export const NODE_ACTIONS_MENU_WIDTH_CLASS_NAME = 'w-[240px] rounded-lg'
export const NODE_ACTIONS_MENU_ITEM_WITH_SHORTCUT_CLASS_NAME = 'w-auto justify-between gap-4'
export const NODE_ACTIONS_MENU_DELETE_ITEM_CLASS_NAME = `${NODE_ACTIONS_MENU_ITEM_WITH_SHORTCUT_CLASS_NAME} text-text-secondary data-highlighted:bg-state-destructive-hover data-highlighted:text-text-destructive`
export function NodeActionsMenuItemContent({
children,
@@ -17,9 +17,6 @@ import Item from './class-item'
const i18nPrefix = 'nodes.questionClassifiers'
// Layout constants
const HANDLE_SIDE_WIDTH = 3 // Width offset for drag handle spacing
type Props = {
nodeId: string
list: Topic[]
@@ -107,7 +104,7 @@ const ClassList: FC<Props> = ({
{!collapsed && (
<div
ref={listContainerRef}
className={cn('overflow-y-visible', `pl-${HANDLE_SIDE_WIDTH}`)}
className="overflow-y-visible pl-3"
>
<ReactSortable
list={list.map(item => ({ ...item }))}
@@ -130,8 +127,7 @@ const ClassList: FC<Props> = ({
<div
key={item.id}
className={cn(
'group relative rounded-[10px] bg-components-panel-bg',
`-ml-${HANDLE_SIDE_WIDTH} min-h-[40px] px-0 py-0`,
'group relative -ml-3 min-h-[40px] rounded-[10px] bg-components-panel-bg px-0 py-0',
)}
style={{
// Performance hint for browser
-1
View File
@@ -64,7 +64,6 @@ const LocaleLayout = async ({
defaultTheme="system"
enableSystem
disableTransitionOnChange
enableColorScheme={false}
>
<NuqsAdapter>
<TanstackQueryInitializer>
+11 -78
View File
@@ -1,79 +1,12 @@
@import './preflight.css' layer(base);
@import './tailwind-core.css';
@import '@langgenius/dify-ui/styles.css';
@import '../../themes/manual-light.css' layer(base);
@import '../../themes/manual-dark.css' layer(base);
@import './monaco-sticky-fix.css' layer(base);
@import '../components/base/action-button/index.css';
@import '../components/base/badge/index.css';
@import '../components/base/premium-badge/index.css';
@import '../components/base/segmented-control/index.css';
@import 'tailwindcss';
@config '../../tailwind.config.ts';
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}
@layer components {
html {
color-scheme: light;
}
html[data-theme='dark'] {
color-scheme: dark;
}
html[data-changing-theme] * {
transition: none !important;
}
[class*='code-'] {
@apply font-mono;
}
.text-gradient {
background: linear-gradient(91.58deg, #2250f2 -29.55%, #0ebcf3 75.22%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
[data-theme='dark'] [data-hide-on-theme='dark'],
[data-theme='light'] [data-hide-on-theme='light'] {
display: none;
}
/* Shiki code block line numbers */
.shiki-line-numbers code {
counter-reset: line;
}
.shiki-line-numbers .line::before {
counter-increment: line;
content: counter(line);
display: inline-block;
width: 1rem;
margin-right: 0.75rem;
text-align: right;
color: var(--color-text-quaternary);
user-select: none;
}
}
@source '../../app';
@source '../../context';
@source '../../hooks';
@source '../../../packages/dify-ui/src';
@source '../../node_modules/streamdown/dist';
@source '../../node_modules/@streamdown/math/dist';
@source not '../../**/*.{spec,test}.{js,ts,jsx,tsx}';
@source not '../../**/*.stories.{js,ts,jsx,tsx}';
@source not '../../../packages/dify-ui/src/**/*.{spec,test}.{ts,tsx}';
@source not '../../../packages/dify-ui/src/**/*.stories.{ts,tsx}';
+5 -7
View File
@@ -1,15 +1,13 @@
/* Ensures Monaco sticky header and other sticky headers remain visible in dark mode */
html[data-theme="dark"] .monaco-editor .sticky-widget {
background-color: var(--color-components-sticky-header-bg) !important;
border-bottom: 1px solid var(--color-components-sticky-header-border) !important;
background-color: var(--color-monaco-sticky-header-bg) !important;
border-bottom: 1px solid var(--color-monaco-sticky-header-border) !important;
box-shadow: var(--vscode-editorStickyScroll-shadow) 0 4px 2px -2px !important;
}
html[data-theme="dark"] .monaco-editor .sticky-line-content:hover {
background-color: var(--color-components-sticky-header-bg-hover) !important;
background-color: var(--color-monaco-sticky-header-bg-hover) !important;
}
/* Monaco editor specific sticky scroll styles in dark mode */
html[data-theme="dark"] .monaco-editor .sticky-line-root {
background-color: var(--color-components-sticky-header-bg) !important;
}
background-color: var(--color-monaco-sticky-header-bg) !important;
}
+21
View File
@@ -0,0 +1,21 @@
/*
* Pre-bound icons plugin used by `web/`. Combines Iconify's heroicons and
* remix icon packs with the project's custom public and vendor sprites.
* Wired into Tailwind v4 via `@plugin './plugins/icons.ts';` in tailwind-core.css.
*/
import { icons as customPublicIcons } from '@dify/iconify-collections/custom-public'
import { icons as customVenderIcons } from '@dify/iconify-collections/custom-vender'
import { getIconCollections, iconsPlugin } from '@egoist/tailwindcss-icons'
export default iconsPlugin({
collections: {
...getIconCollections(['heroicons', 'ri']),
'custom-public': customPublicIcons,
'custom-vender': customVenderIcons,
},
extraProperties: {
width: '1rem',
height: '1rem',
display: 'block',
},
})
+17
View File
@@ -0,0 +1,17 @@
/*
* `@tailwindcss/typography` configured with Dify's prose color tokens.
* Injects `theme.typography` for v4 CSS-first via plugin `config` merge.
*/
import typographyPlugin from '@tailwindcss/typography'
import typographyConfig from './typography-config.js'
const created = typographyPlugin()
export default {
handler: created.handler,
config: {
theme: {
typography: typographyConfig,
},
},
}
+141
View File
@@ -0,0 +1,141 @@
/*
* Tailwind CSS v4 shared core for `web/`. CSS-first: no tailwind.config.ts.
*
* Layers, JS plugins, project-only design tokens, and app-level CSS are
* declared here. Environment-specific entry files declare source scanning.
*/
@layer theme, base, components, utilities;
/* Tailwind core — selective layer imports skip preflight; we ship our own
* (see ./preflight.css) so cross-app baseline stays controlled. */
@import 'tailwindcss/theme.css' layer(theme);
@import 'tailwindcss/utilities.css' layer(utilities);
/* Local preflight (replaces v3 `corePlugins.preflight: false`). */
@import './preflight.css' layer(base);
/* Design system: palette overrides, semantic tokens, light/dark themes,
* project utilities and components. */
@import '@langgenius/dify-ui/styles.css';
/* Project-only runtime CSS variables (gradients and special masks). */
@import '../../themes/manual-light.css' layer(base);
@import '../../themes/manual-dark.css' layer(base);
@import './monaco-sticky-fix.css' layer(base);
/* Component CSS using @apply / @utility. */
@import '../components/base/action-button/index.css';
@import '../components/base/badge/index.css';
@import '../components/base/premium-badge/index.css';
@import '../components/base/segmented-control/index.css';
/* ---------- JS plugins ------------------------------------------------ */
@plugin './plugins/icons.ts';
@plugin './plugins/typography.ts';
/* ---------- Project-only theme tokens --------------------------------- */
@theme {
/* Additional breakpoints layered on top of v4 defaults. */
--breakpoint-mobile: 100px;
--breakpoint-tablet: 640px;
--breakpoint-pc: 769px;
--breakpoint-2k: 2560px;
/* Custom animations. */
--animate-spin-slow: spin 2s linear infinite;
}
/* Background-image / gradient utilities. Values resolve at runtime from
* manual-light.css / manual-dark.css. Using @theme inline so the variable
* indirection survives without re-declaring values at :root. */
@theme inline {
/* Flat color (used as `bg-background-gradient-bg-fill-chat-bubble-bg-3`). */
--color-background-gradient-bg-fill-chat-bubble-bg-3: var(--color-background-gradient-bg-fill-chat-bubble-bg-3);
/* Gradients — registered under v4's --background-image-* namespace. */
--background-image-chatbot-bg: var(--color-chatbot-bg);
--background-image-chat-bubble-bg: var(--color-chat-bubble-bg);
--background-image-chat-input-mask: var(--color-chat-input-mask);
--background-image-workflow-process-bg: var(--color-workflow-process-bg);
--background-image-workflow-process-paused-bg: var(--color-workflow-process-paused-bg);
--background-image-workflow-run-failed-bg: var(--color-workflow-run-failed-bg);
--background-image-workflow-batch-failed-bg: var(--color-workflow-batch-failed-bg);
--background-image-mask-top2bottom-gray-50-to-transparent: var(--mask-top2bottom-gray-50-to-transparent);
--background-image-marketplace-divider-bg: var(--color-marketplace-divider-bg);
--background-image-marketplace-plugin-empty: var(--color-marketplace-plugin-empty);
--background-image-toast-success-bg: var(--color-toast-success-bg);
--background-image-toast-warning-bg: var(--color-toast-warning-bg);
--background-image-toast-error-bg: var(--color-toast-error-bg);
--background-image-toast-info-bg: var(--color-toast-info-bg);
--background-image-app-detail-bg: var(--color-app-detail-bg);
--background-image-app-detail-overlay-bg: var(--color-app-detail-overlay-bg);
--background-image-dataset-chunk-process-success-bg: var(--color-dataset-chunk-process-success-bg);
--background-image-dataset-chunk-process-error-bg: var(--color-dataset-chunk-process-error-bg);
--background-image-dataset-chunk-detail-card-hover-bg: var(--color-dataset-chunk-detail-card-hover-bg);
--background-image-dataset-child-chunk-expand-btn-bg: var(--color-dataset-child-chunk-expand-btn-bg);
--background-image-dataset-option-card-blue-gradient: var(--color-dataset-option-card-blue-gradient);
--background-image-dataset-option-card-purple-gradient: var(--color-dataset-option-card-purple-gradient);
--background-image-dataset-option-card-orange-gradient: var(--color-dataset-option-card-orange-gradient);
--background-image-dataset-chunk-list-mask-bg: var(--color-dataset-chunk-list-mask-bg);
--background-image-line-divider-bg: var(--color-line-divider-bg);
--background-image-dataset-warning-message-bg: var(--color-dataset-warning-message-bg);
--background-image-price-premium-badge-background: var(--color-premium-badge-background);
--background-image-premium-yearly-tip-text-background: var(--color-premium-yearly-tip-text-background);
--background-image-price-premium-text-background: var(--color-premium-text-background);
--background-image-price-enterprise-background: var(--color-price-enterprise-background);
--background-image-grid-mask-background: var(--color-grid-mask-background);
--background-image-node-data-source-bg: var(--color-node-data-source-bg);
--background-image-tag-selector-mask-bg: var(--color-tag-selector-mask-bg);
--background-image-tag-selector-mask-hover-bg: var(--color-tag-selector-mask-hover-bg);
--background-image-pipeline-template-card-hover-bg: var(--color-pipeline-template-card-hover-bg);
--background-image-pipeline-add-documents-title-bg: var(--color-pipeline-add-documents-title-bg);
--background-image-billing-plan-title-bg: var(--color-billing-plan-title-bg);
--background-image-billing-plan-card-premium-bg: var(--color-billing-plan-card-premium-bg);
--background-image-billing-plan-card-enterprise-bg: var(--color-billing-plan-card-enterprise-bg);
--background-image-knowledge-pipeline-creation-footer-bg: var(--color-knowledge-pipeline-creation-footer-bg);
--background-image-progress-bar-indeterminate-stripe: var(--color-progress-bar-indeterminate-stripe);
--background-image-chat-answer-human-input-form-divider-bg: var(--color-chat-answer-human-input-form-divider-bg);
}
/* ---------- Backwards-compat: gray-200 default border color ----------- *
* v4 changed the default border color to `currentColor`. Preserve the v3
* baseline used throughout the codebase. */
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}
/* ---------- App-level component CSS ----------------------------------- */
@layer components {
[class*='code-'] {
@apply font-mono;
}
.text-gradient {
background: linear-gradient(91.58deg, #2250f2 -29.55%, #0ebcf3 75.22%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Shiki code block line numbers */
.shiki-line-numbers code {
counter-reset: line;
}
.shiki-line-numbers .line::before {
counter-increment: line;
content: counter(line);
display: inline-block;
width: 1rem;
margin-right: 0.75rem;
text-align: right;
color: var(--color-text-quaternary);
user-select: none;
}
}
-91
View File
@@ -1,91 +0,0 @@
import { icons as customPublicIcons } from '@dify/iconify-collections/custom-public'
import { icons as customVenderIcons } from '@dify/iconify-collections/custom-vender'
import { getIconCollections, iconsPlugin } from '@egoist/tailwindcss-icons'
import difyUIPreset from '@langgenius/dify-ui/tailwind-preset'
import tailwindTypography from '@tailwindcss/typography'
import typography from './typography.js'
const config = {
presets: [difyUIPreset],
theme: {
typography,
extend: {
screens: {
'mobile': '100px',
'tablet': '640px',
'pc': '769px',
'2k': '2560px',
},
backgroundColor: {
'background-gradient-bg-fill-chat-bubble-bg-3': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-3)',
},
backgroundImage: {
'chatbot-bg': 'var(--color-chatbot-bg)',
'chat-bubble-bg': 'var(--color-chat-bubble-bg)',
'chat-input-mask': 'var(--color-chat-input-mask)',
'workflow-process-bg': 'var(--color-workflow-process-bg)',
'workflow-process-paused-bg': 'var(--color-workflow-process-paused-bg)',
'workflow-run-failed-bg': 'var(--color-workflow-run-failed-bg)',
'workflow-batch-failed-bg': 'var(--color-workflow-batch-failed-bg)',
'mask-top2bottom-gray-50-to-transparent': 'var(--mask-top2bottom-gray-50-to-transparent)',
'marketplace-divider-bg': 'var(--color-marketplace-divider-bg)',
'marketplace-plugin-empty': 'var(--color-marketplace-plugin-empty)',
'toast-success-bg': 'var(--color-toast-success-bg)',
'toast-warning-bg': 'var(--color-toast-warning-bg)',
'toast-error-bg': 'var(--color-toast-error-bg)',
'toast-info-bg': 'var(--color-toast-info-bg)',
'app-detail-bg': 'var(--color-app-detail-bg)',
'app-detail-overlay-bg': 'var(--color-app-detail-overlay-bg)',
'dataset-chunk-process-success-bg': 'var(--color-dataset-chunk-process-success-bg)',
'dataset-chunk-process-error-bg': 'var(--color-dataset-chunk-process-error-bg)',
'dataset-chunk-detail-card-hover-bg': 'var(--color-dataset-chunk-detail-card-hover-bg)',
'dataset-child-chunk-expand-btn-bg': 'var(--color-dataset-child-chunk-expand-btn-bg)',
'dataset-option-card-blue-gradient': 'var(--color-dataset-option-card-blue-gradient)',
'dataset-option-card-purple-gradient': 'var(--color-dataset-option-card-purple-gradient)',
'dataset-option-card-orange-gradient': 'var(--color-dataset-option-card-orange-gradient)',
'dataset-chunk-list-mask-bg': 'var(--color-dataset-chunk-list-mask-bg)',
'line-divider-bg': 'var(--color-line-divider-bg)',
'dataset-warning-message-bg': 'var(--color-dataset-warning-message-bg)',
'price-premium-badge-background': 'var(--color-premium-badge-background)',
'premium-yearly-tip-text-background': 'var(--color-premium-yearly-tip-text-background)',
'price-premium-text-background': 'var(--color-premium-text-background)',
'price-enterprise-background': 'var(--color-price-enterprise-background)',
'grid-mask-background': 'var(--color-grid-mask-background)',
'node-data-source-bg': 'var(--color-node-data-source-bg)',
'tag-selector-mask-bg': 'var(--color-tag-selector-mask-bg)',
'tag-selector-mask-hover-bg': 'var(--color-tag-selector-mask-hover-bg)',
'pipeline-template-card-hover-bg': 'var(--color-pipeline-template-card-hover-bg)',
'pipeline-add-documents-title-bg': 'var(--color-pipeline-add-documents-title-bg)',
'billing-plan-title-bg': 'var(--color-billing-plan-title-bg)',
'billing-plan-card-premium-bg': 'var(--color-billing-plan-card-premium-bg)',
'billing-plan-card-enterprise-bg': 'var(--color-billing-plan-card-enterprise-bg)',
'knowledge-pipeline-creation-footer-bg': 'var(--color-knowledge-pipeline-creation-footer-bg)',
'progress-bar-indeterminate-stripe': 'var(--color-progress-bar-indeterminate-stripe)',
'chat-answer-human-input-form-divider-bg': 'var(--color-chat-answer-human-input-form-divider-bg)',
},
animation: {
'spin-slow': 'spin 2s linear infinite',
},
},
},
plugins: [
tailwindTypography,
iconsPlugin({
collections: {
...getIconCollections(['heroicons', 'ri']),
'custom-public': customPublicIcons,
'custom-vender': customVenderIcons,
},
extraProperties: {
width: '1rem',
height: '1rem',
display: 'block',
},
}),
],
corePlugins: {
preflight: false,
},
}
export default config
-18
View File
@@ -1,18 +0,0 @@
import type { Config } from 'tailwindcss'
import commonConfig from './tailwind-common-config'
const config: Config = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./context/**/*.{js,ts,jsx,tsx}',
'../packages/dify-ui/src/**/*.{ts,tsx}',
'./node_modules/streamdown/dist/*.js',
'./node_modules/@streamdown/math/dist/*.js',
'!./**/*.{spec,test}.{js,ts,jsx,tsx}',
'!../packages/dify-ui/src/**/*.{spec,test}.{ts,tsx}',
],
...commonConfig,
}
export default config
+7
View File
@@ -1,4 +1,11 @@
html[data-theme="dark"] {
--color-monaco-sticky-header-bg: var(--color-components-panel-bg);
--color-monaco-sticky-header-bg-hover: var(--color-components-panel-on-panel-item-bg-hover);
--color-monaco-sticky-header-border: var(--color-components-panel-border);
--vscode-editorStickyScroll-background: var(--color-monaco-sticky-header-bg);
--vscode-editorStickyScrollHover-background: var(--color-monaco-sticky-header-bg-hover);
--vscode-editorStickyScroll-border: var(--color-monaco-sticky-header-border);
--vscode-editorStickyScroll-shadow: rgba(0, 0, 0, 0.6);
--color-chatbot-bg: linear-gradient(180deg,
rgba(34, 34, 37, 0.9) 0%,
rgba(29, 29, 32, 0.9) 90.48%);