Tailwind 4 geçişi

This commit is contained in:
Sedat Öztürk 2026-10-17 00:13:31 +03:00
parent 48e7d34026
commit a56bdc3e79
227 changed files with 3511 additions and 11204 deletions

View file

@ -128,18 +128,18 @@ DevExtreme bileşenleri bu metadata'ya göre kendini kurar.
| Bileşen | Sürüm / Notlar | | Bileşen | Sürüm / Notlar |
| --- | --- | | --- | --- |
| React | 19.2 | | React | 19.3 |
| Build | Vite 8 + TypeScript 5.9 | | Build | Vite 8 + TypeScript 7.0 (native `tsc`), lint: oxlint |
| UI kütüphaneleri | DevExtreme 26.1 (React), Tailwind CSS 3.4, kendi `components/ui` tasarım sistemi | | UI kütüphaneleri | DevExtreme 26.1 (React), Tailwind CSS 4.3 (`@tailwindcss/vite`, CSS-first yapılandırma), kendi `components/ui` tasarım sistemi |
| Routing | react-router-dom 7 (dinamik route üretimi) | | Routing | react-router-dom 7 (dinamik route üretimi) |
| State | easy-peasy (global store) + @tanstack/react-query | | State | easy-peasy (global store) |
| Form | Formik + Yup, DevExtreme Form | | Form | Formik + Yup, DevExtreme Form |
| Kod editörü | Monaco Editor | | Kod editörü | Monaco Editor |
| Runtime derleme | @babel/standalone (Custom Component) | | Runtime derleme | @babel/standalone 8 (Custom Component; JSX `classic` runtime) |
| Takvim/Gantt | DevExtreme Scheduler/Gantt | | Takvim/Gantt | DevExtreme Scheduler/Gantt |
| Gerçek zamanlı | @microsoft/signalr | | Gerçek zamanlı | @microsoft/signalr |
| PWA | vite-plugin-pwa (Workbox) | | PWA | vite-plugin-pwa 2 (Workbox 7) |
| Node | 24.13 / npm 11 (`volta` ile sabitlenmiş) | | Node | 24.22 / npm 12 (`volta` ile sabitlenmiş; kurulum betikleri `allowScripts` ile yönetilir) |
--- ---
@ -1140,12 +1140,25 @@ kaynak seed dosyalarıdır (`configs/seeds/*/data/App.DeveloperKit.CustomCompone
depo kökünde, `ui/` dışındadır — derleme bağlamı yalnızca `ui/` klasörü olduğunda (docker, ayrı depo kökünde, `ui/` dışındadır — derleme bağlamı yalnızca `ui/` klasörü olduğunda (docker, ayrı
checkout) glob boş döner ve seed'e özgü sınıflar (`md:col-span-4`, `bg-gray-950/80`, `opacity-20`) checkout) glob boş döner ve seed'e özgü sınıflar (`md:col-span-4`, `bg-gray-950/80`, `opacity-20`)
CSS'e hiç girmez: uygulama yerelde doğru, sunucuda stilsiz görünür. Bu yüzden aynı sınıflar var CSS'e hiç girmez: uygulama yerelde doğru, sunucuda stilsiz görünür. Bu yüzden aynı sınıflar var
olan `ui/safelist.txt` dosyasına da yazılır. Dosyayı zaten `twSafelistGenerator` eklentisi üretiyor olan `ui/safelist.txt` dosyasına da yazılır. Dosyayı `ui/twSafelistGenerator.ts` Vite eklentisi
(renk/ölçü listesi); eklenti artık seed dosyalarındaki `className` değerlerini de toplayıp üretir: seed dosyalarındaki `className` değerlerini toplar, derleme başında yazar ve geliştirmede seed
`# --- custom component classes ---` işaretinin altına ekliyor. `safelist.txt` `ui/` içinde ve klasörünü izler. `safelist.txt` `ui/` içinde ve depoda olduğu için her ortamda taranır
depoda olduğu için her ortamda taranır. Seed kökü görünmüyorsa işaretin altındaki liste olduğu gibi (`src/assets/styles/tailwind/index.css` → `@source`). Seed kökü görünmüyorsa liste olduğu gibi
korunur — eksik bir bağlam listeyi silip sorunu büyütmez. Ayrı bir betik ya da ikinci bir safelist korunur — eksik bir bağlam listeyi silip sorunu büyütmez. Çalışma anında veriden gelen renk/ölçü
dosyası yoktur; liste her `npm run build` / `npm start` ile tazelenir. sınıfları (`bg-{renk}-{ton}`, `w-1/2` …) dosyaya değil aynı CSS'teki `@source inline(...)` satırlarına
yazılır. Ayrı bir betik ya da ikinci bir safelist dosyası yoktur; liste her `npm run build` /
`npm start` ile tazelenir.
**Tailwind 4 yapılandırması.** `tailwind.config.ts` ve PostCSS zinciri yoktur; tema (`gray` paleti,
`sozsoft-*` renkleri, `1.2`–`1.4` aralıkları, font) `src/assets/styles/tailwind/index.css` içindeki
`@theme` bloğundadır. Aynı dosya v3 davranışını koruyan uyumluluk kurallarını taşır: `dark` sınıf
varyantı, dokunmatikte de çalışan `hover`, gri-200 kenarlık, gri-400 placeholder, butonda `pointer`
imleci, varsayılan 3px mavi `ring`, veritabanındaki eski Custom Component kodu için `flex-shrink-*` /
`flex-grow-*`. Kademelenme v3 ile aynıdır (`app.css`): yalnızca tema ve preflight katmandadır
(en zayıf); `components/` + `template/` stilleri ve en sonda utility'ler katmansızdır. Bileşen
stilleri katmana alınmaz — katmansız CSS her katmanı yendiği için stilini katmansız basan
kütüphanelere (react-select, DevExtreme) yenilirdi. JS'te renk gerektiğinde değer kopyalanmaz,
`themeColor()` (`src/utils/tailwind.ts`) temanın `var(--color-*)` değişkenini döndürür.
**Katalog düğümleri.** Kanvasın doğrudan çizdiği, derlenen bileşen listesinde yer almayan **Katalog düğümleri.** Kanvasın doğrudan çizdiği, derlenen bileşen listesinde yer almayan
bileşenler tek bir sözlükte durur (`RUNTIME_NODE_COMPONENTS`): kanvas onu `VisualCanvas` içinde, bileşenler tek bir sözlükte durur (`RUNTIME_NODE_COMPONENTS`): kanvas onu `VisualCanvas` içinde,
@ -2104,8 +2117,8 @@ Ayrıntılı kurulum notları: [`configs/deployment/README.md`](configs/deployme
cd ui cd ui
npm start # geliştirme sunucusu npm start # geliştirme sunucusu
npm run build # üretim derlemesi (metadata + version + vite build) npm run build # üretim derlemesi (metadata + version + vite build)
npm run lint # ESLint npm run lint # oxlint (.oxlintrc.json)
npm run format # prettier --write + eslint --fix npm run format # prettier --write + oxlint --fix
``` ```
### 21.3. Backend ### 21.3. Backend

View file

@ -519,8 +519,11 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
olmadığını kontrol et. olmadığını kontrol et.
- **Custom component sınıfları** → bileşen kodu veritabanında yaşar, Tailwind derlemede yalnızca - **Custom component sınıfları** → bileşen kodu veritabanında yaşar, Tailwind derlemede yalnızca
seed dosyasını görür. Seed dosyası `ui/` dışında olduğu için aynı sınıflar `ui/safelist.txt` seed dosyasını görür. Seed dosyası `ui/` dışında olduğu için aynı sınıflar `ui/safelist.txt`
sonuna da yazılır (`twSafelistGenerator`, derlemede otomatik); yoksa uygulama sunucuda stilsiz dosyasına da yazılır (`ui/twSafelistGenerator.ts` Vite eklentisi, derlemede otomatik); yoksa
kalır. İkinci bir safelist dosyası açma. uygulama sunucuda stilsiz kalır. İkinci bir safelist dosyası açma. Çalışma anında veriden üretilen
sınıf (`bg-${renk}-500`) dosyaya değil `src/assets/styles/tailwind/index.css`'teki `@source inline`
satırına eklenir. Sınıf adları Tailwind 4'tür (`shadow-xs`, `rounded-sm`, `bg-black/50`,
`shrink-0`, `x!`); tema `tailwind.config.ts`'te değil aynı dosyanın `@theme` bloğundadır.
- **Custom component kaydı/silinmesi** → `data/App.DeveloperKit.CustomComponents/{Id}.json` - **Custom component kaydı/silinmesi** → `data/App.DeveloperKit.CustomComponents/{Id}.json`
(Custom Components ekranının seed verisi); ekran klasör modundadır, her bileşen kendi satır (Custom Components ekranının seed verisi); ekran klasör modundadır, her bileşen kendi satır
dosyasındadır. Hem listeden hem Visual Designer'dan (`CustomComponentAppService`) yapılan kayıt dosyasındadır. Hem listeden hem Visual Designer'dan (`CustomComponentAppService`) yapılan kayıt

View file

@ -11,7 +11,7 @@
"Description": null, "Description": null,
"IsActive": true, "IsActive": true,
"Dependencies": "", "Dependencies": "",
"Code": "import React, { useEffect, useState } from \"react\";\nimport axios from \"axios\";\n\ninterface DynamicEntityComponentProps {\n title: string;\n}\n\nconst api = axios.create({\n baseURL: \"https://localhost:44344/\",\n});\n\nconst DynamicEntityComponent: React.FC<DynamicEntityComponentProps> = ({ title }) => {\n const [data, setData] = useState<Array<{ id: string; name: string }>>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchData = async () => {\n setLoading(true);\n setError(null);\n\n try {\n const res = await api.get(`/api/app/crudendpoint/${title}`);\n const raw = Array.isArray(res.data) ? res.data : res.data?.items ?? [];\n\n const filtered = raw.map((item: any) => ({\n id: item.Id ?? item.id,\n name: item.Name ?? item.name,\n }));\n\n setData(filtered);\n } catch (err: any) {\n setError(err.message || \"Failed to fetch data\");\n } finally {\n setLoading(false);\n }\n };\n\n if (title) fetchData();\n }, [title]);\n\n if (loading) return <div>Loading...</div>;\n if (error) return <div className=\"text-red-600 dark:text-red-400\">Error: {error}</div>;\n if (!data.length) return <div>No records found</div>;\n\n const headers = [\"id\", \"name\", \"actions\"];\n\n return (\n <div className=\"overflow-auto\">\n <table className=\"min-w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 shadow-sm rounded-lg\">\n <thead className=\"bg-slate-100 dark:bg-slate-800\">\n <tr>\n {headers.map((key) => (\n <th\n key={key}\n className=\"text-left px-4 py-2 border-b border-slate-200 dark:border-slate-700 text-sm font-medium text-slate-700 dark:text-slate-200\"\n >\n {key === \"actions\" ? \"Actions\" : key}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((item, rowIndex) => (\n <tr key={item.id ?? rowIndex} className=\"hover:bg-slate-50 dark:hover:bg-slate-800\">\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.id}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.name}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800\">\n <Button\n type=\"button\"\n color=\"blue-500\"\n onClick={() => alert(item.name)}\n shape=\"round\"\n size=\"xs\"\n variant=\"solid\"\n id=\"c_mrix4c1a_qrybhk\"\n >\n Show Name\n </Button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n};\n\nexport default DynamicEntityComponent;", "Code": "import React, { useEffect, useState } from \"react\";\nimport axios from \"axios\";\n\ninterface DynamicEntityComponentProps {\n title: string;\n}\n\nconst api = axios.create({\n baseURL: \"https://localhost:44344/\",\n});\n\nconst DynamicEntityComponent: React.FC<DynamicEntityComponentProps> = ({ title }) => {\n const [data, setData] = useState<Array<{ id: string; name: string }>>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchData = async () => {\n setLoading(true);\n setError(null);\n\n try {\n const res = await api.get(`/api/app/crudendpoint/${title}`);\n const raw = Array.isArray(res.data) ? res.data : res.data?.items ?? [];\n\n const filtered = raw.map((item: any) => ({\n id: item.Id ?? item.id,\n name: item.Name ?? item.name,\n }));\n\n setData(filtered);\n } catch (err: any) {\n setError(err.message || \"Failed to fetch data\");\n } finally {\n setLoading(false);\n }\n };\n\n if (title) fetchData();\n }, [title]);\n\n if (loading) return <div>Loading...</div>;\n if (error) return <div className=\"text-red-600 dark:text-red-400\">Error: {error}</div>;\n if (!data.length) return <div>No records found</div>;\n\n const headers = [\"id\", \"name\", \"actions\"];\n\n return (\n <div className=\"overflow-auto\">\n <table className=\"min-w-full bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-700 shadow-xs rounded-lg\">\n <thead className=\"bg-slate-100 dark:bg-slate-800\">\n <tr>\n {headers.map((key) => (\n <th\n key={key}\n className=\"text-left px-4 py-2 border-b border-slate-200 dark:border-slate-700 text-sm font-medium text-slate-700 dark:text-slate-200\"\n >\n {key === \"actions\" ? \"Actions\" : key}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((item, rowIndex) => (\n <tr key={item.id ?? rowIndex} className=\"hover:bg-slate-50 dark:hover:bg-slate-800\">\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.id}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800 text-sm text-slate-800 dark:text-slate-100\">\n {item.name}\n </td>\n <td className=\"px-4 py-2 border-b border-slate-100 dark:border-slate-800\">\n <Button\n type=\"button\"\n color=\"blue-500\"\n onClick={() => alert(item.name)}\n shape=\"round\"\n size=\"xs\"\n variant=\"solid\"\n id=\"c_mrix4c1a_qrybhk\"\n >\n Show Name\n </Button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n};\n\nexport default DynamicEntityComponent;",
"Props": null, "Props": null,
"DataSources": "", "DataSources": "",
"LastModificationTime": null, "LastModificationTime": null,

44
ui/.oxlintrc.json Normal file
View file

@ -0,0 +1,44 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "react", "import", "oxc"],
"categories": {
"correctness": "error"
},
"env": {
"browser": true,
"es2024": true
},
"settings": {
"react": { "version": "19" }
},
"rules": {
"react/rules-of-hooks": "error",
"react/exhaustive-deps": "warn",
"react/only-export-components": ["warn", { "allowConstantExport": true }],
"react/react-in-jsx-scope": "off",
"react/set-state-in-effect": "off",
"react/refs": "off",
"react/immutability": "off",
"react/static-components": "off",
"react/preserve-manual-memoization": "off",
"react/purity": "off",
"react/use-memo": "off",
"react/no-did-update-set-state": "off",
"no-eval": "off",
"import/first": "warn",
"import/newline-after-import": "warn",
"import/no-duplicates": "error",
"import/default": "off",
"import/no-named-as-default": "off",
"import/no-named-as-default-member": "off",
"typescript/no-explicit-any": "off",
"no-unused-vars": "off"
},
"overrides": [
{
"files": ["vite.config.ts", "twSafelistGenerator.ts"],
"env": { "browser": false, "node": true }
}
],
"ignorePatterns": ["dist/**", "dev-dist/**", "public/**", "env.d.ts"]
}

View file

@ -3,7 +3,7 @@
"vscode.typescript-language-features", "vscode.typescript-language-features",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
"dbaemuer.vscode-eslint", "oxc.oxc-vscode",
"vscode.npm" "vscode.npm"
] ]
} }

View file

@ -1,8 +1,10 @@
ARG ENV="dev" ARG ENV="dev"
FROM node:24-alpine FROM node:24.22-alpine
ARG ENV=$ENV ARG ENV=$ENV
RUN apk add --no-cache ca-certificates && update-ca-certificates # Node/npm sürümü package.json `volta` alanıyla aynıdır.
RUN apk add --no-cache ca-certificates && update-ca-certificates && \
npm install -g npm@12.2.0
ENV GENERATE_SOURCEMAP=false ENV GENERATE_SOURCEMAP=false
ENV NODE_OPTIONS=--max-old-space-size=16384 ENV NODE_OPTIONS=--max-old-space-size=16384

View file

@ -1,102 +0,0 @@
import js from '@eslint/js'
import tsParser from '@typescript-eslint/parser'
import tsPlugin from '@typescript-eslint/eslint-plugin'
import importPlugin from 'eslint-plugin-import'
import reactPlugin from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import prettier from 'eslint-config-prettier'
import globals from 'globals'
export default [
{
ignores: [
'node_modules/**',
'dist/**',
'dev-dist/**',
'public/**',
'env.d.ts',
],
},
js.configs.recommended,
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: globals.browser,
parserOptions: { ecmaFeatures: { jsx: true } },
},
plugins: {
import: importPlugin,
react: reactPlugin,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
settings: {
react: { version: 'detect' },
'import/parsers': { '@typescript-eslint/parser': ['.ts', '.tsx'] },
'import/resolver': {
typescript: { project: './tsconfig.eslint.json', alwaysTryTypes: true },
},
// Vite'in sanal modulleri diskte yoktur; cozucu onlari bulamaz, tipleri
// `vite-env.d.ts` uzerinden gelir.
'import/core-modules': ['virtual:pwa-register'],
},
rules: {
...reactPlugin.configs.recommended.rules,
...reactPlugin.configs['jsx-runtime'].rules,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
...importPlugin.configs.recommended.rules,
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'react/react-in-jsx-scope': 'off',
'import/first': 'warn',
'import/default': 'off',
'import/newline-after-import': 'warn',
'import/no-named-as-default-member': 'off',
'import/no-duplicates': 'error',
'import/no-named-as-default': 'off',
'react/prop-types': 'off',
'react/jsx-sort-props': [
'warn',
{
callbacksLast: true,
shorthandFirst: true,
ignoreCase: true,
reservedFirst: true,
noSortAlphabetically: true,
},
],
},
},
{
files: ['**/*.{ts,tsx}'],
languageOptions: { parser: tsParser },
plugins: { '@typescript-eslint': tsPlugin },
rules: {
...tsPlugin.configs.recommended.rules,
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
// TypeScript zaten tanimsiz tanimlayicilari yakalar; ESLint'in kapsam
// analizi ise `EventListener` / `NotificationOptions` gibi yalnizca tip
// olarak var olan DOM global'lerini bilmedigi icin yanlis alarm veriyor.
// typescript-eslint'in de onerdigi ayar.
'no-undef': 'off',
},
},
prettier,
// Derleme araclari Node'da CommonJS olarak calisir: tarayici globalleri yerine Node
// globalleri gecerlidir ve Tailwind eklentisi `require` ile yuklenir (tailwind.config.ts
// Node tarafindan okunur, bundle'a girmez).
{
files: ['tailwind.config.ts', 'postcss.config.cjs', 'twSafelistGenerator/**/*.js'],
languageOptions: {
globals: globals.node,
sourceType: 'commonjs',
},
rules: {
'@typescript-eslint/no-require-imports': 'off',
},
},
]

6513
ui/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,8 +3,8 @@
"private": true, "private": true,
"elstarVersion": "2.1.6", "elstarVersion": "2.1.6",
"engines": { "engines": {
"node": ">=24.19.0", "node": ">=24.22.0",
"npm": ">=11.19.0" "npm": ">=12.2.0"
}, },
"type": "module", "type": "module",
"scripts": { "scripts": {
@ -17,82 +17,67 @@
"build:production": "vite build", "build:production": "vite build",
"preview": "vite preview", "preview": "vite preview",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"lint": "eslint .", "lint": "oxlint",
"lint:fix": "npm run lint -- --fix", "lint:fix": "oxlint --fix",
"prettier": "prettier --ignore-path .gitignore src --check", "prettier": "prettier --ignore-path .gitignore src --check",
"prettier:fix": "npm run prettier -- --write", "prettier:fix": "npm run prettier -- --write",
"format": "npm run prettier:fix && npm run lint:fix" "format": "npm run prettier:fix && npm run lint:fix"
}, },
"dependencies": { "dependencies": {
"@babel/standalone": "^7.29.8", "@babel/standalone": "^8.0.7",
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0", "@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2", "@dnd-kit/utilities": "^3.2.2",
"@floating-ui/react": "^0.27.20", "@floating-ui/react": "^0.27.20",
"@marsidev/react-turnstile": "^1.6.0", "@marsidev/react-turnstile": "^1.6.2",
"@microsoft/signalr": "^10.0.11", "@microsoft/signalr": "^10.0.11",
"@monaco-editor/react": "^4.7.0", "@monaco-editor/react": "^4.7.0",
"@tanstack/react-table": "^8.21.3", "axios": "^1.20.0",
"axios": "^1.19.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"dayjs": "^1.11.21", "dayjs": "^1.11.23",
"devexpress-reporting-react": "26.1.4", "devexpress-reporting-react": "26.1.5",
"devextreme": "26.1.4", "devextreme": "26.1.5",
"devextreme-exceljs-fork": "^4.4.13", "devextreme-exceljs-fork": "^4.5.0",
"devextreme-react": "26.1.4", "devextreme-react": "26.1.5",
"dompurify": "3.4.13", "dompurify": "3.4.17",
"easy-peasy": "^6.1.1", "easy-peasy": "^6.1.1",
"emoji-picker-react": "^4.19.1", "emoji-picker-react": "^5.0.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"formik": "^2.4.9", "formik": "^2.4.9",
"framer-motion": "^13.1.0", "framer-motion": "^14.3.0",
"jspdf": "^4.2.1", "jspdf": "^4.2.1",
"react": "^19.2.8", "react": "^19.3.1",
"react-advanced-cropper": "^0.20.1", "react-advanced-cropper": "^0.20.1",
"react-arborist": "^3.16.0", "react-dom": "^19.3.1",
"react-dom": "^19.2.8",
"react-icons": "^5.7.0", "react-icons": "^5.7.0",
"react-modal": "^3.16.3", "react-modal": "^3.16.3",
"react-router-dom": "^7.18.2", "react-router-dom": "^7.18.4",
"react-select": "^5.10.2", "react-select": "^5.10.2",
"yup": "^1.7.1", "yup": "^1.7.1",
"zxing-wasm": "^3.1.4" "zxing-wasm": "^3.1.5"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.39.5",
"@tailwindcss/typography": "^0.5.20", "@tailwindcss/typography": "^0.5.20",
"@tailwindcss/vite": "^4.3.3",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
"@types/node": "^24.10.1", "@types/node": "^24.19.2",
"@types/react": "^19.2.18", "@types/react": "^19.3.0",
"@types/react-dom": "^19.2.4", "@types/react-dom": "^19.3.0",
"@types/react-modal": "^3.16.3", "@types/react-modal": "^3.16.3",
"@typescript-eslint/eslint-plugin": "^8.67.0", "@vitejs/plugin-react": "^6.1.2",
"@typescript-eslint/parser": "^8.67.0", "oxlint": "^1.88.0",
"@vitejs/plugin-react": "^6.0.5", "prettier": "^3.9.10",
"autoprefixer": "^10.5.4", "tailwindcss": "^4.3.3",
"cssnano": "^8.0.5", "typescript": "^7.0.2",
"eslint": "^9.39.5", "vite": "^8.3.4",
"eslint-config-prettier": "^10.1.8", "vite-plugin-pwa": "^2.0.0",
"eslint-import-resolver-typescript": "^4.4.5", "workbox-build": "^7.4.1",
"eslint-plugin-import": "^2.32.0", "workbox-window": "^7.4.1"
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.4",
"globals": "^17.11.0",
"postcss": "^8.5.26",
"prettier": "^3.9.6",
"tailwindcss": "^3.4.19",
"typescript": "5.9",
"vite": "^8.2.1",
"vite-plugin-pwa": "^1.3.0"
}, },
"overrides": { "overrides": {
"dompurify": "3.4.13",
"glob": "13.0.6", "glob": "13.0.6",
"brace-expansion@1": "1.1.18", "dompurify": "3.4.17",
"brace-expansion@2": "2.1.4", "postcss-selector-parser": "7.1.6",
"brace-expansion@5": "5.0.9",
"fast-uri": "3.1.5",
"workbox-build": { "workbox-build": {
"source-map": "0.8.0" "source-map": "0.8.0"
}, },
@ -101,7 +86,12 @@
} }
}, },
"volta": { "volta": {
"node": "24.19.0", "node": "24.22.0",
"npm": "11.19.0" "npm": "12.2.0"
},
"allowScripts": {
"core-js": false,
"unrs-resolver": false,
"inferno": false
} }
} }

View file

@ -1,8 +0,0 @@
module.exports = {
plugins: {
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
cssnano: {},
},
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,8 @@
/* v3 kademelenmesi: preflight ve tema katmanda (en zayif), bilesen stilleri ve utility'ler
katmansiz. Katmansiz CSS her katmani yendigi icin bilesen stilleri katmana alinsaydi
react-select/DevExtreme gibi stilini katmansiz basan kutuphanelere yenilirdi; utility'ler
en sonda oldugu icin esit ozgullukte bilesen stilini ezer. */
@import './tailwind/index.css';
@import './components/index.css'; @import './components/index.css';
@import './template/index.css'; @import './template/index.css';
@import './tailwind/index.css'; @import 'tailwindcss/utilities.css' source(none);

View file

@ -10,7 +10,7 @@
@apply w-full px-3 rounded-lg border border-gray-300 dark:border-gray-600 @apply w-full px-3 rounded-lg border border-gray-300 dark:border-gray-600
bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
placeholder-gray-400 dark:placeholder-gray-500 placeholder-gray-400 dark:placeholder-gray-500
focus:outline-none focus:ring-2 focus:border-transparent focus:outline-hidden focus:ring-2 focus:border-transparent
transition-colors duration-150 text-sm; transition-colors duration-150 text-sm;
} }

View file

@ -1,5 +1,5 @@
.button { .button {
@apply font-semibold focus:outline-none whitespace-nowrap; @apply font-semibold focus:outline-hidden whitespace-nowrap;
&.radius-round { &.radius-round {
@apply rounded-md; @apply rounded-md;

View file

@ -7,7 +7,7 @@
} }
.card-shadow { .card-shadow {
@apply shadow border-b border-gray-200 dark:border-gray-600 dark:border-none; @apply shadow-sm border-b border-gray-200 dark:border-gray-600 dark:border-none;
} }
.card-header-border { .card-header-border {

View file

@ -4,11 +4,11 @@
border border
border-gray-300 border-gray-300
dark:border-gray-600 dark:border-gray-600
rounded rounded-sm
cursor-pointer cursor-pointer
inline-block inline-block
align-middle align-middle
flex-shrink-0 shrink-0
p-0 p-0
appearance-none appearance-none
transition-colors transition-colors

View file

@ -20,7 +20,7 @@
@apply inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-sm @apply inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-sm
bg-indigo-100 dark:bg-indigo-900/40 bg-indigo-100 dark:bg-indigo-900/40
text-indigo-700 dark:text-indigo-300 text-indigo-700 dark:text-indigo-300
select-none outline-none select-none outline-hidden
focus-visible:ring-2 focus-visible:ring-indigo-500; focus-visible:ring-2 focus-visible:ring-indigo-500;
} }
@ -40,6 +40,6 @@
/* Input */ /* Input */
.chips-input { .chips-input {
@apply flex-1 min-w-[80px] outline-none bg-transparent text-sm @apply flex-1 min-w-[80px] outline-hidden bg-transparent text-sm
text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500; text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500;
} }

View file

@ -1,7 +1,7 @@
.close-btn { .close-btn {
@apply outline-none; @apply outline-hidden;
} }
.close-btn-default { .close-btn-default {
@apply text-xl rounded p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300; @apply text-xl rounded-sm p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300;
} }

View file

@ -14,9 +14,9 @@
} }
/* Sizes */ /* Sizes */
.color-picker-sm .color-picker-swatch { @apply w-6 h-6 rounded; } .color-picker-sm .color-picker-swatch { @apply w-6 h-6 rounded-sm; }
.color-picker-lg .color-picker-swatch { @apply w-10 h-10 rounded-lg; } .color-picker-lg .color-picker-swatch { @apply w-10 h-10 rounded-lg; }
.color-picker-xs .color-picker-swatch { @apply w-5 h-5 rounded; } .color-picker-xs .color-picker-swatch { @apply w-5 h-5 rounded-sm; }
/* Native hidden input */ /* Native hidden input */
.color-picker-native { .color-picker-native {
@ -80,7 +80,7 @@
.color-picker-text-input { .color-picker-text-input {
@apply w-full text-sm px-2 py-1 rounded-md border border-gray-300 dark:border-gray-600 @apply w-full text-sm px-2 py-1 rounded-md border border-gray-300 dark:border-gray-600
bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-gray-100 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-gray-100
focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:border-transparent
font-mono; font-mono;
} }

View file

@ -10,7 +10,7 @@
margin: 0 !important; margin: 0 !important;
} }
@screen sm { @media (width >= theme(--breakpoint-sm)) {
.dialog { .dialog {
@apply max-w-xl; @apply max-w-xl;
} }
@ -19,7 +19,7 @@
} }
} }
@screen md { @media (width >= theme(--breakpoint-md)) {
.dialog { .dialog {
@apply max-w-2xl; @apply max-w-2xl;
} }
@ -28,7 +28,7 @@
} }
} }
@screen lg { @media (width >= theme(--breakpoint-lg)) {
.dialog { .dialog {
@apply max-w-4xl; @apply max-w-4xl;
} }
@ -37,7 +37,7 @@
} }
} }
@screen xl { @media (width >= theme(--breakpoint-xl)) {
.dialog { .dialog {
@apply max-w-6xl; @apply max-w-6xl;
} }
@ -51,7 +51,7 @@
@apply p-6 rounded-lg shadow-xl my-4 relative bg-white dark:bg-gray-800 flex flex-col overflow-hidden; @apply p-6 rounded-lg shadow-xl my-4 relative bg-white dark:bg-gray-800 flex flex-col overflow-hidden;
} }
@screen sm { @media (width >= theme(--breakpoint-sm)) {
.dialog-content { .dialog-content {
max-height: calc(100vh - 8rem); max-height: calc(100vh - 8rem);
@apply my-16; @apply my-16;
@ -60,7 +60,7 @@
.dialog-header, .dialog-header,
.dialog-footer { .dialog-footer {
@apply flex-shrink-0; @apply shrink-0;
} }
.dialog-body { .dialog-body {
@ -80,7 +80,7 @@
.dialog-overlay { .dialog-overlay {
transition: all 0.15s ease-in-out; transition: all 0.15s ease-in-out;
@apply bg-opacity-60 inset-0 fixed z-30 bg-black dark:bg-opacity-80; @apply bg-black/60 dark:bg-black/80 inset-0 fixed z-30;
} }
.dialog-overlay-after-open { .dialog-overlay-after-open {

View file

@ -30,7 +30,7 @@
.drawer-overlay { .drawer-overlay {
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
@apply bg-black bg-opacity-80 inset-0 fixed z-30; @apply bg-black/80 inset-0 fixed z-30;
} }
.drawer-overlay-after-open { .drawer-overlay-after-open {

View file

@ -4,7 +4,7 @@
.dropdown-menu { .dropdown-menu {
min-width: 160px; min-width: 160px;
@apply rounded-md shadow-lg bg-white dark:bg-gray-700 dark:shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none p-1.5 absolute z-30; @apply rounded-md shadow-lg bg-white dark:bg-gray-700 dark:shadow-2xl ring-1 ring-black/5 focus:outline-hidden p-1.5 absolute z-30;
&.top-start { &.top-start {
@apply ltr:left-0 rtl:right-0 bottom-full origin-bottom; @apply ltr:left-0 rtl:right-0 bottom-full origin-bottom;

View file

@ -27,12 +27,12 @@
} }
.image-viewer-toolbar-actions button { .image-viewer-toolbar-actions button {
@apply p-1.5 rounded text-white/70 hover:text-white hover:bg-white/10 @apply p-1.5 rounded-sm text-white/70 hover:text-white hover:bg-white/10
transition-colors duration-150; transition-colors duration-150;
} }
.image-viewer-close { .image-viewer-close {
@apply ml-2 !text-white/90 hover:!text-red-400; @apply ml-2 text-white/90! hover:!text-red-400;
} }
/* Stage */ /* Stage */
@ -69,7 +69,7 @@
} }
.image-viewer-thumb { .image-viewer-thumb {
@apply w-14 h-14 rounded overflow-hidden border-2 border-transparent @apply w-14 h-14 rounded-sm overflow-hidden border-2 border-transparent
opacity-50 hover:opacity-80 transition-all duration-150 shrink-0 p-0; opacity-50 hover:opacity-80 transition-all duration-150 shrink-0 p-0;
} }

View file

@ -6,7 +6,7 @@
rounded-md rounded-md
w-full w-full
py-2 px-3 py-2 px-3
focus:outline-none focus:outline-hidden
focus:ring-1 focus:ring-1
focus-within:ring-1 focus-within:ring-1
appearance-none appearance-none

View file

@ -3,7 +3,7 @@
} }
.knob { .knob {
@apply select-none outline-none; @apply select-none outline-hidden;
touch-action: none; touch-action: none;
} }

View file

@ -26,14 +26,14 @@
} }
&.menu-item-themed { &.menu-item-themed {
@apply text-gray-100 text-opacity-80; @apply text-gray-100/80;
&.menu-item-hoverable { &.menu-item-hoverable {
@apply hover:text-opacity-100 hover:bg-gray-900 hover:bg-opacity-10; @apply hover:text-gray-100 hover:bg-gray-900/10;
} }
&.menu-item-active { &.menu-item-active {
@apply text-gray-100 bg-gray-900 bg-opacity-30 hover:bg-opacity-30; @apply text-gray-100 bg-gray-900/30 hover:bg-gray-900/30;
} }
} }
@ -62,7 +62,7 @@
} }
&.menu-collapse-item-themed { &.menu-collapse-item-themed {
@apply text-gray-100 text-opacity-80 hover:text-opacity-100 hover:bg-gray-900 hover:bg-opacity-10; @apply text-gray-100/80 hover:text-gray-100 hover:bg-gray-900/10;
} }
&.menu-collapse-item-transparent { &.menu-collapse-item-transparent {

View file

@ -10,7 +10,7 @@
} }
&.menu-title-themed { &.menu-title-themed {
@apply text-gray-100 text-opacity-50; @apply text-gray-100/50;
} }
} }

View file

@ -3,7 +3,7 @@
} }
.pagination-pager { .pagination-pager {
@apply cursor-pointer relative mx-1 rounded inline-flex items-center h-8 w-8 justify-center text-sm font-semibold select-none; @apply cursor-pointer relative mx-1 rounded-sm inline-flex items-center h-8 w-8 justify-center text-sm font-semibold select-none;
} }
.pagination-pager-inactive { .pagination-pager-inactive {

View file

@ -8,7 +8,7 @@
cursor-pointer cursor-pointer
inline-block inline-block
align-middle align-middle
flex-shrink-0 shrink-0
p-0 p-0
appearance-none appearance-none
transition-colors transition-colors

View file

@ -1,5 +1,5 @@
.rate { .rate {
@apply inline-flex items-center select-none outline-none; @apply inline-flex items-center select-none outline-hidden;
} }
.rate-star { .rate-star {
@ -7,5 +7,5 @@
} }
.rate-star:focus-visible { .rate-star:focus-visible {
@apply outline-2 outline-offset-2 outline-indigo-500 rounded; @apply outline-2 outline-offset-2 outline-indigo-500 rounded-sm;
} }

View file

@ -22,7 +22,7 @@
.segment-item-default { .segment-item-default {
@apply font-semibold @apply font-semibold
focus:outline-none focus:outline-hidden
cursor-pointer cursor-pointer
select-none select-none
rounded-md rounded-md

View file

@ -43,7 +43,7 @@
} }
.select__multi-value { .select__multi-value {
@apply rounded text-sm; @apply rounded-sm text-sm;
} }
} }
@ -56,7 +56,7 @@
} }
.select__multi-value { .select__multi-value {
@apply rounded text-xs; @apply rounded-sm text-xs;
} }
} }
@ -79,7 +79,7 @@
&.hide-single-value { &.hide-single-value {
.select__single-value { .select__single-value {
@apply !hidden; @apply hidden!;
} }
} }
} }

View file

@ -7,5 +7,5 @@
} }
.skeleton-block { .skeleton-block {
@apply rounded h-2.5 w-full; @apply rounded-sm h-2.5 w-full;
} }

View file

@ -47,7 +47,7 @@
/* Handle */ /* Handle */
.slider-handle { .slider-handle {
@apply absolute rounded-full bg-white border-2 border-indigo-500 @apply absolute rounded-full bg-white border-2 border-indigo-500
shadow-md cursor-grab z-10 outline-none shadow-md cursor-grab z-10 outline-hidden
focus:ring-2 focus:ring-offset-1 transition-shadow duration-100 focus:ring-2 focus:ring-offset-1 transition-shadow duration-100
hover:shadow-lg; hover:shadow-lg;
top: 50%; top: 50%;
@ -74,18 +74,18 @@
px-1.5 py-0.5 text-xs font-medium px-1.5 py-0.5 text-xs font-medium
bg-gray-800 dark:bg-gray-200 bg-gray-800 dark:bg-gray-200
text-white dark:text-gray-900 text-white dark:text-gray-900
rounded whitespace-nowrap pointer-events-none z-20; rounded-sm whitespace-nowrap pointer-events-none z-20;
} }
.slider-tooltip::after { .slider-tooltip::after {
content: ''; content: '';
@apply absolute left-1/2 -translate-x-1/2 -bottom-1; @apply absolute left-1/2 -translate-x-1/2 -bottom-1;
border: 4px solid transparent; border: 4px solid transparent;
border-top-color: theme('colors.gray.800'); border-top-color: var(--color-gray-800);
} }
.dark .slider-tooltip::after { .dark .slider-tooltip::after {
border-top-color: theme('colors.gray.200'); border-top-color: var(--color-gray-200);
} }
/* Marks */ /* Marks */

View file

@ -53,7 +53,7 @@
} }
.switcher-checked-loading { .switcher-checked-loading {
@apply !text-white; @apply text-white!;
} }
.switcher-uncheck-loading { .switcher-uncheck-loading {

View file

@ -1,5 +1,5 @@
.time-input-field { .time-input-field {
@apply ring-0 w-6 text-center outline-none bg-transparent; @apply ring-0 w-6 text-center outline-hidden bg-transparent;
} }
.time-input-wrapper { .time-input-wrapper {

View file

@ -35,5 +35,5 @@
} }
.timeline-connect { .timeline-connect {
@apply h-full w-[2px] bg-gray-200 dark:bg-gray-600 flex-grow; @apply h-full w-[2px] bg-gray-200 dark:bg-gray-600 grow;
} }

View file

@ -1,6 +1,103 @@
@tailwind base; @layer theme, base;
@tailwind components; @import 'tailwindcss/theme.css' layer(theme);
@tailwind utilities; @import 'tailwindcss/preflight.css' layer(base);
@plugin '@tailwindcss/typography';
@source '../../../../index.html';
@source '../../..';
/* Custom Component siniflari: seed dosyasi `ui/` disinda oldugu icin twSafelistGenerator derlemede
buraya yazar (vite.config.ts). */
@source '../../../../safelist.txt';
/* Calisma aninda veriden gelen siniflar (renk, olcu); kaynakta gecmedikleri icin derlemeye elle
alinir. Renk listesi temanin paletidir (`--color-*`). */
@source inline('{,hover:,dark:,dark:hover:}text-{inherit,current,transparent,black,white,{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-{50,{100..900..100},950},sozsoft-{main,secondary,active,x,y}}');
@source inline('{,hover:,active:,dark:,dark:hover:,dark:active:}bg-{inherit,current,transparent,black,white,{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-{50,{100..900..100},950},sozsoft-{main,secondary,active,x,y}}');
@source inline('{,hover:,focus:,focus-within:}ring-{inherit,current,transparent,black,white,{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-{50,{100..900..100},950},sozsoft-{main,secondary,active,x,y}}');
@source inline('{,focus:,focus-within:}border-{inherit,current,transparent,black,white,{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-{50,{100..900..100},950},sozsoft-{main,secondary,active,x,y}}');
/* Button iki tonlu koyu tema: renk adi calisma aninda gelir. */
@source inline('dark:bg-{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-500/20');
@source inline('dark:hover:bg-{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-500/30');
@source inline('dark:active:bg-{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}-500/40');
@source inline('{h,w,ml,mr}-{0,px,0.5,1,1.2,1.3,1.4,1.5,2,2.5,3,3.5,4,5,6,7,8,9,10,11,12,14,16,20,24,28,32,36,40,44,48,52,56,60,64,72,80,96,auto}');
@source inline('{h,w}-{1/2,1/3,2/3,1/4,2/4,3/4,1/5,2/5,3/5,4/5,1/6,2/6,3/6,4/6,5/6,full,screen,min,max,fit}');
@source inline('h-{svh,lvh,dvh}');
@source inline('w-{1/12,2/12,3/12,4/12,5/12,6/12,7/12,8/12,9/12,10/12,11/12,svw,lvw,dvw}');
@source inline('{,hover:,focus:,active:,dark:,sm:,md:,lg:,xl:,2xl:}{container,block,inline-block,inline-flex,hidden,absolute,relative,fixed,sticky,grid,flex,flex-col,flex-row,flex-wrap,truncate,rounded,border,shadow,uppercase,lowercase,capitalize,backdrop-blur,transition,transform}');
@source inline('{,sm:,md:,lg:,xl:,2xl:}prose{,-sm,-base,-lg,-xl,-2xl}');
@source inline('{,dark:}prose-invert');
@source inline('prose-{slate,gray,zinc,neutral,stone,red,orange,amber,yellow,lime,green,emerald,teal,cyan,sky,blue,indigo,violet,purple,fuchsia,pink,rose}');
/* v4'te kaldirilan adlar: veritabanina daha once kurulmus Custom Component kodu bunlari tasiyabilir
(migrate var olan kaydi ezmez). */
@utility flex-shrink-0 {
flex-shrink: 0;
}
@utility flex-shrink {
flex-shrink: 1;
}
@utility flex-grow-0 {
flex-grow: 0;
}
@utility flex-grow {
flex-grow: 1;
}
@source inline('{,sm:,md:,lg:,xl:,2xl:}{flex-shrink-0,flex-shrink,flex-grow-0,flex-grow}');
@custom-variant dark (&:where(.dark, .dark *));
/* v3 davranisi: hover dokunmatik cihazlarda da calisir. */
@custom-variant hover (&:hover);
@theme {
--font-sans: 'Helvetica Neue', 'Segoe UI', helvetica, verdana, sans-serif;
--color-gray-50: #f8f8f8;
--color-gray-100: #eeeeee;
--color-gray-200: #d6d6d6;
--color-gray-300: #b8b8b8;
--color-gray-400: #929292;
--color-gray-500: #747474;
--color-gray-600: #575757;
--color-gray-700: #3f3f3f;
--color-gray-800: #303030;
--color-gray-900: #252525;
--color-gray-950: #1f1f1f;
--color-sozsoft-main: #ff99c8;
--color-sozsoft-secondary: #fcf6bd;
--color-sozsoft-active: #d0f4de;
--color-sozsoft-x: #a9def9;
--color-sozsoft-y: #e4c1f9;
--spacing-1_2: 0.35rem;
--spacing-1_3: 0.4rem;
--spacing-1_4: 0.45rem;
/* v3 varsayilani: renksiz `ring` 3px yari saydam mavi. */
--default-ring-width: 3px;
--default-ring-color: color-mix(in oklab, var(--color-blue-500) 50%, transparent);
}
/* v4 onyuklemesinin v3'ten farklari: kenarlik rengi, placeholder rengi, buton imleci. */
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
input::placeholder,
textarea::placeholder {
color: var(--color-gray-400);
}
button:not(:disabled),
[role='button']:not(:disabled) {
cursor: pointer;
}
}
@layer base { @layer base {
:root, :root,

View file

@ -15,12 +15,10 @@
} }
.header-action-item-hoverable { .header-action-item-hoverable {
@apply hover:bg-black @apply hover:bg-black/5
hover:bg-opacity-5
hover:text-gray-900 hover:text-gray-900
dark:hover:bg-black dark:hover:bg-black/40
dark:hover:text-gray-100 dark:hover:text-gray-100
dark:hover:bg-opacity-40
transition-colors transition-colors
duration-300 duration-300
ease-in-out; ease-in-out;

View file

@ -36,7 +36,7 @@
} }
.horizontal-menu-themed .menu-item.horizontal-menu-tab-active { .horizontal-menu-themed .menu-item.horizontal-menu-tab-active {
@apply text-opacity-100; @apply text-gray-100;
} }
/* Açılır menü: genel Dropdown'a dokunmadan yalnızca üst menünün panelleri kapsanır. */ /* Açılır menü: genel Dropdown'a dokunmadan yalnızca üst menünün panelleri kapsanır. */

View file

@ -1,5 +1,5 @@
.side-nav { .side-nav {
@apply flex-col flex-auto flex-shrink-0 z-20 transition-all ease-in-out duration-200 print:hidden; @apply flex-col flex-auto shrink-0 z-20 transition-all ease-in-out duration-200 print:hidden;
} }
.side-nav-expand { .side-nav-expand {
@ -7,7 +7,7 @@
} }
.side-nav-content { .side-nav-content {
height: calc(100vh - theme('spacing.24')); height: calc(100vh - --spacing(24));
@apply overflow-y-auto; @apply overflow-y-auto;
} }

View file

@ -1,9 +1,9 @@
.stacked-side-nav { .stacked-side-nav {
@apply flex flex-auto sticky top-0 h-screen flex-shrink-0 z-20 transition-all ease-in-out duration-200 overflow-y-hidden print:hidden; @apply flex flex-auto sticky top-0 h-screen shrink-0 z-20 transition-all ease-in-out duration-200 overflow-y-hidden print:hidden;
} }
.stacked-side-nav-content { .stacked-side-nav-content {
height: calc(100vh - theme("spacing.16")); height: calc(100vh - --spacing(16));
@apply overflow-y-auto; @apply overflow-y-auto;
} }

View file

@ -86,7 +86,7 @@ export const Splitter: React.FC<SplitterProps> = ({
ref={splitterRef} ref={splitterRef}
className={` className={`
${isHorizontal ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'} ${isHorizontal ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'}
bg-gray-300 dark:bg-gray-700 hover:bg-blue-500 dark:hover:bg-blue-600 transition-colors duration-200 flex-shrink-0 bg-gray-300 dark:bg-gray-700 hover:bg-blue-500 dark:hover:bg-blue-600 transition-colors duration-200 shrink-0
${isDragging ? 'bg-blue-500 dark:bg-blue-600' : ''} ${isDragging ? 'bg-blue-500 dark:bg-blue-600' : ''}
`} `}
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}
@ -120,7 +120,7 @@ export const Splitter: React.FC<SplitterProps> = ({
ref={splitterRef} ref={splitterRef}
className={` className={`
${isHorizontal ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'} ${isHorizontal ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'}
bg-gray-300 dark:bg-gray-700 hover:bg-blue-500 dark:hover:bg-blue-600 transition-colors duration-200 flex-shrink-0 bg-gray-300 dark:bg-gray-700 hover:bg-blue-500 dark:hover:bg-blue-600 transition-colors duration-200 shrink-0
${isDragging ? 'bg-blue-500 dark:bg-blue-600' : ''} ${isDragging ? 'bg-blue-500 dark:bg-blue-600' : ''}
`} `}
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}

View file

@ -211,7 +211,7 @@ const STYLE_GROUPS = {
'truncate', 'truncate',
'whitespace-normal', 'whitespace-normal',
'whitespace-nowrap', 'whitespace-nowrap',
'break-words', 'wrap-break-word',
'leading-none', 'leading-none',
'leading-tight', 'leading-tight',
'leading-normal', 'leading-normal',
@ -263,8 +263,8 @@ const STYLE_GROUPS = {
'border-slate-700', 'border-slate-700',
'border-sky-500', 'border-sky-500',
'rounded-none', 'rounded-none',
'rounded-xs',
'rounded-sm', 'rounded-sm',
'rounded',
'rounded-md', 'rounded-md',
'rounded-lg', 'rounded-lg',
'rounded-xl', 'rounded-xl',
@ -275,8 +275,8 @@ const STYLE_GROUPS = {
], ],
Effects: [ Effects: [
'shadow-none', 'shadow-none',
'shadow-xs',
'shadow-sm', 'shadow-sm',
'shadow',
'shadow-md', 'shadow-md',
'shadow-lg', 'shadow-lg',
'shadow-xl', 'shadow-xl',
@ -284,10 +284,10 @@ const STYLE_GROUPS = {
'opacity-50', 'opacity-50',
'opacity-75', 'opacity-75',
'opacity-100', 'opacity-100',
'blur-xs',
'blur-sm', 'blur-sm',
'blur', 'backdrop-blur-xs',
'backdrop-blur-sm', 'backdrop-blur-sm',
'backdrop-blur',
'transition', 'transition',
'transition-all', 'transition-all',
'duration-150', 'duration-150',
@ -307,8 +307,8 @@ const STYLE_GROUPS = {
'pointer-events-auto', 'pointer-events-auto',
'resize', 'resize',
'resize-none', 'resize-none',
'outline-none', 'outline-hidden',
'focus:outline-none', 'focus:outline-hidden',
'hover:opacity-80', 'hover:opacity-80',
'hover:bg-slate-100', 'hover:bg-slate-100',
'focus:ring-2', 'focus:ring-2',
@ -382,7 +382,7 @@ const StyleModal = ({
return ( return (
<div <div
className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 p-4" className="fixed inset-0 z-100 flex items-center justify-center bg-black/60 p-4"
onMouseDown={onClose} onMouseDown={onClose}
> >
<div <div
@ -447,7 +447,7 @@ const StyleModal = ({
{translate('::App.StyleModal.EditValueManually', { property: propertyName })} {translate('::App.StyleModal.EditValueManually', { property: propertyName })}
</label> </label>
<textarea <textarea
className={`w-full rounded-md border border-slate-300 bg-white p-3 font-mono text-xs text-slate-800 outline-none focus:border-sky-500 dark:border-slate-700 dark:bg-slate-900 dark:text-white ${mode === 'css' ? 'min-h-48' : 'min-h-20'}`} className={`w-full rounded-md border border-slate-300 bg-white p-3 font-mono text-xs text-slate-800 outline-hidden focus:border-sky-500 dark:border-slate-700 dark:bg-slate-900 dark:text-white ${mode === 'css' ? 'min-h-48' : 'min-h-20'}`}
placeholder={ placeholder={
mode === 'css' ? '.my-class { color: red; }' : 'my-card selected-state md:wide-card' mode === 'css' ? '.my-class { color: red; }' : 'my-card selected-state md:wide-card'
} }

View file

@ -1658,7 +1658,7 @@ export const CUSTOM_COMPONENTS: ComponentDefinition[] = [
rowSpan: 1, rowSpan: 1,
colStart: 1, colStart: 1,
rowStart: 1, rowStart: 1,
className: 'bg-blue-100 p-4 border rounded', className: 'bg-blue-100 p-4 border rounded-sm',
}, },
{ {
id: 'grid-item-2', id: 'grid-item-2',
@ -1667,7 +1667,7 @@ export const CUSTOM_COMPONENTS: ComponentDefinition[] = [
rowSpan: 1, rowSpan: 1,
colStart: 2, colStart: 2,
rowStart: 1, rowStart: 1,
className: 'bg-green-100 p-4 border rounded', className: 'bg-green-100 p-4 border rounded-sm',
}, },
{ {
id: 'grid-item-3', id: 'grid-item-3',
@ -1676,7 +1676,7 @@ export const CUSTOM_COMPONENTS: ComponentDefinition[] = [
rowSpan: 1, rowSpan: 1,
colStart: 3, colStart: 3,
rowStart: 1, rowStart: 1,
className: 'bg-yellow-100 p-4 border rounded', className: 'bg-yellow-100 p-4 border rounded-sm',
}, },
{ {
id: 'grid-item-4', id: 'grid-item-4',
@ -1685,7 +1685,7 @@ export const CUSTOM_COMPONENTS: ComponentDefinition[] = [
rowSpan: 1, rowSpan: 1,
colStart: 1, colStart: 1,
rowStart: 2, rowStart: 2,
className: 'bg-purple-100 p-4 border rounded', className: 'bg-purple-100 p-4 border rounded-sm',
}, },
{ {
id: 'grid-item-5', id: 'grid-item-5',
@ -1694,7 +1694,7 @@ export const CUSTOM_COMPONENTS: ComponentDefinition[] = [
rowSpan: 1, rowSpan: 1,
colStart: 3, colStart: 3,
rowStart: 2, rowStart: 2,
className: 'bg-red-100 p-4 border rounded', className: 'bg-red-100 p-4 border rounded-sm',
}, },
], ],
category: 'properties', category: 'properties',

View file

@ -1,4 +0,0 @@
declare module '@babel/standalone' {
export function transform(code: string, options?: any): { code: string; map?: any };
export function transformSync(code: string, options?: any): { code: string; map?: any };
}

View file

@ -70,7 +70,7 @@ export default function Widget({
<div <div
onClick={onClick} onClick={onClick}
className={classNames( className={classNames(
'bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 flex flex-col justify-between', 'bg-white dark:bg-gray-900 rounded-lg shadow-xs border border-gray-200 dark:border-gray-700 p-4 flex flex-col justify-between',
onClick && 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800', onClick && 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800',
className className
)} )}
@ -89,7 +89,7 @@ export default function Widget({
</div> </div>
<div <div
className={classNames( className={classNames(
'w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center shadow-sm', 'w-12 h-12 bg-linear-to-br rounded-xl flex items-center justify-center shadow-xs',
colorMap[safeColor].bg, colorMap[safeColor].bg,
'dark:' + colorMap[safeColor].darkBg 'dark:' + colorMap[safeColor].darkBg
)} )}

View file

@ -44,7 +44,7 @@ const DevExtremeBoundary = ({ children }: DevExtremeBoundaryProps) => {
if (configuredCulture !== cultureName) { if (configuredCulture !== cultureName) {
return ( return (
<div className="flex flex-auto flex-col h-[100vh]"> <div className="flex flex-auto flex-col h-screen">
<Loading loading /> <Loading loading />
</div> </div>
) )

View file

@ -142,7 +142,7 @@ export const FileUploadArea: React.FC<FileUploadAreaProps> = ({
<div className="border border-gray-200 dark:border-gray-700 rounded-lg p-4 dark:bg-gray-900/40"> <div className="border border-gray-200 dark:border-gray-700 rounded-lg p-4 dark:bg-gray-900/40">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex items-center space-x-3 min-w-0 flex-1"> <div className="flex items-center space-x-3 min-w-0 flex-1">
<FaFile className="w-8 h-8 text-blue-500 flex-shrink-0" /> <FaFile className="w-8 h-8 text-blue-500 shrink-0" />
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="font-medium text-gray-800 dark:text-gray-100 truncate"> <div className="font-medium text-gray-800 dark:text-gray-100 truncate">
{selectedFile.name} {selectedFile.name}

View file

@ -330,7 +330,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
return ( return (
<div className="flex flex-col w-full mt-4"> <div className="flex flex-col w-full mt-4">
{/* Navigation Tabs */} {/* Navigation Tabs */}
<div className="flex space-x-1 mb-4 bg-white dark:bg-gray-800 dark:border-gray-800 rounded-lg p-1 shadow-sm border border-gray-200 flex-shrink-0"> <div className="flex space-x-1 mb-4 bg-white dark:bg-gray-800 dark:border-gray-800 rounded-lg p-1 shadow-xs border border-gray-200 shrink-0">
{['import', 'preview', 'history'].map((tab) => ( {['import', 'preview', 'history'].map((tab) => (
<Button <Button
key={tab} key={tab}
@ -360,7 +360,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Template Generator - 2/3 width on large screens, full width on mobile */} {/* Template Generator - 2/3 width on large screens, full width on mobile */}
<div className="lg:col-span-2"> <div className="lg:col-span-2">
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700">
<div className="px-3 py-3 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between"> <div className="px-3 py-3 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
<h3 className="text-xl font-semibold text-gray-800 dark:text-gray-100 flex items-center"> <h3 className="text-xl font-semibold text-gray-800 dark:text-gray-100 flex items-center">
<FaDownload className="w-4 h-4 mr-2" /> <FaDownload className="w-4 h-4 mr-2" />
@ -471,7 +471,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
{/* File Upload - 1/3 width on large screens, full width on mobile */} {/* File Upload - 1/3 width on large screens, full width on mobile */}
<div className="lg:col-span-1"> <div className="lg:col-span-1">
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-4 h-full"> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700 p-4 h-full">
<h2 className="text-xl font-semibold text-gray-800 dark:text-gray-100 mb-4 flex items-center"> <h2 className="text-xl font-semibold text-gray-800 dark:text-gray-100 mb-4 flex items-center">
<FaUpload className="w-5 h-5 mr-2 text-green-500" /> <FaUpload className="w-5 h-5 mr-2 text-green-500" />
{translate('::App.ListFormImportManager.UploadData')} {translate('::App.ListFormImportManager.UploadData')}
@ -509,7 +509,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
)} )}
</div> </div>
) : ( ) : (
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-12"> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700 p-12">
<div className="text-center text-gray-500 dark:text-gray-400"> <div className="text-center text-gray-500 dark:text-gray-400">
<FaEye className="w-16 h-16 mx-auto mb-4 text-gray-300 dark:text-gray-600" /> <FaEye className="w-16 h-16 mx-auto mb-4 text-gray-300 dark:text-gray-600" />
<div className="text-xl font-medium mb-2"> <div className="text-xl font-medium mb-2">
@ -523,7 +523,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
)} )}
{activeTab === 'history' && ( {activeTab === 'history' && (
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700">
<div className="divide-y divide-gray-100 dark:divide-gray-800"> <div className="divide-y divide-gray-100 dark:divide-gray-800">
{importHistory.map((session) => ( {importHistory.map((session) => (
<div <div
@ -643,7 +643,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
: 'bg-green-50 text-green-700 border border-green-200 dark:bg-gray-800 dark:text-green-300 dark:border-gray-700' : 'bg-green-50 text-green-700 border border-green-200 dark:bg-gray-800 dark:text-green-300 dark:border-gray-700'
}`} }`}
> >
<span className="mt-0.5 flex-shrink-0"> <span className="mt-0.5 shrink-0">
{session.status === 'executed_with_errors' || {session.status === 'executed_with_errors' ||
session.status === 'failed' || session.status === 'failed' ||
session.status === 'execute_failed' ? ( session.status === 'execute_failed' ? (
@ -660,7 +660,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
{/* Execute Details Section */} {/* Execute Details Section */}
{expandedSessions.has(session.id) && ( {expandedSessions.has(session.id) && (
<div className="mt-3 bg-gradient-to-r from-indigo-50 to-blue-50 dark:from-gray-800 dark:to-gray-800 border border-indigo-100 dark:border-gray-700 rounded-lg shadow-sm hover:shadow-md transition-shadow"> <div className="mt-3 bg-linear-to-r from-indigo-50 to-blue-50 dark:from-gray-800 dark:to-gray-800 border border-indigo-100 dark:border-gray-700 rounded-lg shadow-xs hover:shadow-md transition-shadow">
<div className="p-3"> <div className="p-3">
{loadingExecutes.has(session.id) ? ( {loadingExecutes.has(session.id) ? (
<div className="flex items-center space-x-2 text-gray-500 dark:text-gray-400 py-2"> <div className="flex items-center space-x-2 text-gray-500 dark:text-gray-400 py-2">
@ -676,7 +676,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
<div key={execute.id} className="p-3 rounded-lg dark:bg-gray-900/40"> <div key={execute.id} className="p-3 rounded-lg dark:bg-gray-900/40">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
{/* Sol: Tarih */} {/* Sol: Tarih */}
<div className="flex-shrink-0"> <div className="shrink-0">
<div className="text-lg text-gray-500 dark:text-gray-400"> <div className="text-lg text-gray-500 dark:text-gray-400">
{new Date(execute.creationTime).toLocaleString()} {new Date(execute.creationTime).toLocaleString()}
</div> </div>
@ -711,7 +711,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
</div> </div>
{/* Sağ: Status */} {/* Sağ: Status */}
<div className="flex items-center space-x-2 flex-shrink-0"> <div className="flex items-center space-x-2 shrink-0">
{getExecuteStatusIcon(execute.status)} {getExecuteStatusIcon(execute.status)}
<div <div
className={`text-xs font-medium ${getExecuteStatusColor(execute.status)}`} className={`text-xs font-medium ${getExecuteStatusColor(execute.status)}`}
@ -753,7 +753,7 @@ export const ImportDashboard: React.FC<ImportDashboardProps> = ({ gridDto }) =>
</Button> </Button>
{expandedErrors.has(execute.id) && ( {expandedErrors.has(execute.id) && (
<div className="mt-2 max-h-48 overflow-y-auto rounded border border-orange-200 bg-orange-50 dark:border-gray-700 dark:bg-gray-800"> <div className="mt-2 max-h-48 overflow-y-auto rounded-sm border border-orange-200 bg-orange-50 dark:border-gray-700 dark:bg-gray-800">
{parseErrors(execute.errorsJson).length > 0 ? ( {parseErrors(execute.errorsJson).length > 0 ? (
<table className="w-full text-xs"> <table className="w-full text-xs">
<thead className="bg-orange-100 dark:bg-gray-800 sticky top-0"> <thead className="bg-orange-100 dark:bg-gray-800 sticky top-0">

View file

@ -147,12 +147,12 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
} }
return ( return (
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700">
{/* Header */} {/* Header */}
<div className="p-3 border-b border-gray-200 dark:border-gray-700"> <div className="p-3 border-b border-gray-200 dark:border-gray-700">
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-center gap-4"> <div className="flex flex-col lg:flex-row lg:items-center lg:justify-center gap-4">
{/* Başlık kısmı - Üstte mobile, solda desktop */} {/* Başlık kısmı - Üstte mobile, solda desktop */}
<div className="flex items-center order-1 lg:order-none"> <div className="flex items-center order-1 lg:order-0">
<FaEye className="w-5 h-5 mr-2 text-blue-500" /> <FaEye className="w-5 h-5 mr-2 text-blue-500" />
<h3 className="text-xl font-semibold text-gray-800 dark:text-gray-100"> <h3 className="text-xl font-semibold text-gray-800 dark:text-gray-100">
{translate('::App.ListFormImportManager.ImportPreviewTitle')} {translate('::App.ListFormImportManager.ImportPreviewTitle')}
@ -160,7 +160,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
</div> </div>
{/* İstatistik kartları - Mobile'da alt alta, desktop'ta yan yana */} {/* İstatistik kartları - Mobile'da alt alta, desktop'ta yan yana */}
<div className="order-3 lg:order-none lg:absolute lg:left-1/2 lg:transform lg:-translate-x-1/2"> <div className="order-3 lg:order-0 lg:absolute lg:left-1/2 lg:transform lg:-translate-x-1/2">
<div className="flex flex-col sm:flex-row justify-center gap-2"> <div className="flex flex-col sm:flex-row justify-center gap-2">
<div className="text-center px-3 py-1 bg-blue-50 dark:bg-gray-800 rounded-full border border-blue-200 dark:border-gray-700 font-bold text-blue-600 dark:text-blue-300"> <div className="text-center px-3 py-1 bg-blue-50 dark:bg-gray-800 rounded-full border border-blue-200 dark:border-gray-700 font-bold text-blue-600 dark:text-blue-300">
{previewData?.rows?.length || session.totalRows || 0}{' '} {previewData?.rows?.length || session.totalRows || 0}{' '}
@ -172,7 +172,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
</div> </div>
{/* Durum göstergesi - Altta mobile, sağda desktop */} {/* Durum göstergesi - Altta mobile, sağda desktop */}
<div className="flex justify-center lg:justify-end items-center order-2 lg:order-none lg:ml-auto w-full lg:w-auto"> <div className="flex justify-center lg:justify-end items-center order-2 lg:order-0 lg:ml-auto w-full lg:w-auto">
<span <span
className={`px-3 py-1 rounded-full text-sm font-medium border w-full lg:w-auto text-center ${getStatusColor( className={`px-3 py-1 rounded-full text-sm font-medium border w-full lg:w-auto text-center ${getStatusColor(
session.status, session.status,
@ -201,7 +201,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
type="checkbox" type="checkbox"
checked={selectAll} checked={selectAll}
onChange={handleSelectAll} onChange={handleSelectAll}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded-sm border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
</th> </th>
{previewData.headers.map((header: string, index: number) => ( {previewData.headers.map((header: string, index: number) => (
@ -228,7 +228,7 @@ export const ImportPreview: React.FC<ImportPreviewProps> = ({
type="checkbox" type="checkbox"
checked={selectedRows.includes(rowIndex)} checked={selectedRows.includes(rowIndex)}
onChange={() => handleRowSelect(rowIndex)} onChange={() => handleRowSelect(rowIndex)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded-sm border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
</td> </td>
{row.map((cell, cellIndex) => ( {row.map((cell, cellIndex) => (

View file

@ -59,7 +59,7 @@ export const ImportProgress: React.FC<ImportProgressProps> = ({ session }) => {
} }
return ( return (
<div className="bg-white dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-6"> <div className="bg-white dark:bg-gray-900 rounded-xl shadow-xs border border-gray-200 dark:border-gray-700 p-6">
<div className="text-center space-y-6"> <div className="text-center space-y-6">
{/* Status Icon */} {/* Status Icon */}
<div className="flex justify-center">{getStatusIcon()}</div> <div className="flex justify-center">{getStatusIcon()}</div>

View file

@ -9,7 +9,7 @@ const AuthLayout = () => {
const layoutType = useStoreState((state) => state.theme.layout.type) const layoutType = useStoreState((state) => state.theme.layout.type)
return ( return (
<div className="app-layout-blank flex flex-auto flex-col h-[100vh]"> <div className="app-layout-blank flex flex-auto flex-col h-screen">
{layoutType === LAYOUT_TYPE_BLANK ? ( {layoutType === LAYOUT_TYPE_BLANK ? (
<View /> <View />
) : ( ) : (

View file

@ -26,7 +26,7 @@ const ConfiguratorToggle = () => {
const BlankLayout = () => { const BlankLayout = () => {
return ( return (
<div className="app-layout-blank flex flex-auto flex-col h-[100vh]"> <div className="app-layout-blank flex flex-auto flex-col h-screen">
<View /> <View />
<ConfiguratorToggle /> <ConfiguratorToggle />
<SidePanel className="hidden" /> <SidePanel className="hidden" />

View file

@ -48,7 +48,7 @@ const ClassicLayout = () => {
<div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full"> <div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full">
<Header <Header
container={false} container={false}
className="shadow dark:shadow-2xl" className="shadow-sm dark:shadow-2xl"
headerStart={<HeaderActionsStart />} headerStart={<HeaderActionsStart />}
headerEnd={<HeaderActionsEnd />} headerEnd={<HeaderActionsEnd />}
/> />

View file

@ -43,7 +43,7 @@ const DeckedLayout = () => {
<div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full"> <div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full">
<Header <Header
container={false} container={false}
className="shadow dark:shadow-2xl" className="shadow-sm dark:shadow-2xl"
headerStart={<HeaderActionsStart />} headerStart={<HeaderActionsStart />}
headerEnd={<HeaderActionsEnd />} headerEnd={<HeaderActionsEnd />}
/> />

View file

@ -68,7 +68,7 @@ class LayoutChunkErrorBoundary extends Component<{ children: ReactNode }, { fail
</p> </p>
<button <button
type="button" type="button"
className="rounded bg-indigo-600 px-4 py-2 text-sm font-medium text-white" className="rounded-sm bg-indigo-600 px-4 py-2 text-sm font-medium text-white"
onClick={() => window.location.reload()} onClick={() => window.location.reload()}
> >
Reload Reload
@ -145,7 +145,7 @@ const Layout = () => {
if (loading) { if (loading) {
return ( return (
<div className="flex flex-auto flex-col h-[100vh]"> <div className="flex flex-auto flex-col h-screen">
<Loading loading /> <Loading loading />
</div> </div>
) )
@ -158,7 +158,7 @@ const Layout = () => {
<SkipToContent /> <SkipToContent />
<Suspense <Suspense
fallback={ fallback={
<div className="flex flex-auto flex-col h-[100vh]"> <div className="flex flex-auto flex-col h-screen">
<Loading loading /> <Loading loading />
</div> </div>
} }

View file

@ -31,7 +31,7 @@ const PublicLayout = () => {
{isComponentRegistered(PUBLIC_HEADER_COMPONENT) && {isComponentRegistered(PUBLIC_HEADER_COMPONENT) &&
renderComponent(PUBLIC_HEADER_COMPONENT)} renderComponent(PUBLIC_HEADER_COMPONENT)}
<main className="flex-grow" id="main-content"> <main className="grow" id="main-content">
<View /> <View />
</main> </main>

View file

@ -43,7 +43,7 @@ const SimpleLayout = () => {
<div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full"> <div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full">
<Header <Header
container={false} container={false}
className="shadow dark:shadow-2xl" className="shadow-sm dark:shadow-2xl"
headerStart={<HeaderActionsStart />} headerStart={<HeaderActionsStart />}
headerMiddle={<HorizontalNav />} headerMiddle={<HorizontalNav />}
headerEnd={<HeaderActionsEnd />} headerEnd={<HeaderActionsEnd />}

View file

@ -42,7 +42,7 @@ const StackedSideLayout = () => {
<div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full"> <div className="flex flex-col flex-auto min-h-screen min-w-0 relative w-full">
<Header <Header
container={false} container={false}
className="shadow dark:shadow-2xl" className="shadow-sm dark:shadow-2xl"
headerStart={<HeaderActionsStart />} headerStart={<HeaderActionsStart />}
headerEnd={<HeaderActionsEnd />} headerEnd={<HeaderActionsEnd />}
/> />

View file

@ -52,7 +52,7 @@ export const Basket: React.FC<BasketProps> = ({
return ( return (
<div className="fixed inset-0 z-50 overflow-hidden"> <div className="fixed inset-0 z-50 overflow-hidden">
<div className="absolute inset-0 bg-black bg-opacity-50" onClick={onClose} /> <div className="absolute inset-0 bg-black/50" onClick={onClose} />
<div className="absolute right-0 top-0 h-full w-full max-w-md bg-white shadow-xl dark:bg-gray-900"> <div className="absolute right-0 top-0 h-full w-full max-w-md bg-white shadow-xl dark:bg-gray-900">
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">

View file

@ -32,8 +32,8 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
return ( return (
<div <div
className={`sticky z-20 bg-white border-b border-gray-200 shadow-sm mb-6 transition-all duration-300 dark:border-gray-800 dark:bg-gray-900 dark:shadow-gray-950/40 ${ className={`sticky z-20 bg-white border-b border-gray-200 shadow-xs mb-6 transition-all duration-300 dark:border-gray-800 dark:bg-gray-900 dark:shadow-gray-950/40 ${
isScrolled ? 'top-[6rem]' : 'top-[6.5rem]' isScrolled ? 'top-24' : 'top-26'
}`} }`}
> >
<div className="p-2"> <div className="p-2">

View file

@ -156,7 +156,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({ onBack, onComplete, ba
<form onSubmit={handleSubmit} className="flex flex-col lg:flex-row gap-6"> <form onSubmit={handleSubmit} className="flex flex-col lg:flex-row gap-6">
{/* 3 Sütun: Ödeme Yöntemi | Taksit Seçenekleri | Sipariş Özeti */} {/* 3 Sütun: Ödeme Yöntemi | Taksit Seçenekleri | Sipariş Özeti */}
<div className="w-full lg:w-1/3 flex flex-col gap-6"> <div className="w-full lg:w-1/3 flex flex-col gap-6">
<div className="bg-white rounded-xl shadow border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40"> <div className="bg-white rounded-xl shadow-sm border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40">
<h2 className="text-lg font-semibold mb-4 flex items-center text-gray-900 dark:text-gray-100"> <h2 className="text-lg font-semibold mb-4 flex items-center text-gray-900 dark:text-gray-100">
<FaCalendarAlt className="w-5 h-5 text-green-600 mr-2" /> <FaCalendarAlt className="w-5 h-5 text-green-600 mr-2" />
Lisans Bilgileri Lisans Bilgileri
@ -198,7 +198,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({ onBack, onComplete, ba
<div className="w-full lg:w-1/3 flex flex-col gap-6"> <div className="w-full lg:w-1/3 flex flex-col gap-6">
{/* 1. Sütun: Ödeme Yöntemi */} {/* 1. Sütun: Ödeme Yöntemi */}
<div className="bg-white rounded-xl shadow border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40"> <div className="bg-white rounded-xl shadow-sm border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40">
<h2 className="text-lg font-semibold mb-4 flex items-center"> <h2 className="text-lg font-semibold mb-4 flex items-center">
<FaLock className="w-5 h-5 text-green-600 mr-2" />{' '} <FaLock className="w-5 h-5 text-green-600 mr-2" />{' '}
{translate('::App.Listform.ListformField.PaymentMethodId')} {translate('::App.Listform.ListformField.PaymentMethodId')}
@ -209,7 +209,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({ onBack, onComplete, ba
key={method.id} key={method.id}
className={`group flex items-center gap-3 rounded-xl border p-4 cursor-pointer transition-all ${ className={`group flex items-center gap-3 rounded-xl border p-4 cursor-pointer transition-all ${
selectedPaymentMethod === method.name selectedPaymentMethod === method.name
? 'border-blue-500 bg-blue-50 shadow-sm ring-1 ring-blue-500/20 dark:border-blue-400 dark:bg-blue-950/30 dark:ring-blue-400/20' ? 'border-blue-500 bg-blue-50 shadow-xs ring-1 ring-blue-500/20 dark:border-blue-400 dark:bg-blue-950/30 dark:ring-blue-400/20'
: 'border-gray-200 bg-white hover:border-blue-300 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-950/40 dark:hover:border-blue-500 dark:hover:bg-gray-800/70' : 'border-gray-200 bg-white hover:border-blue-300 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-950/40 dark:hover:border-blue-500 dark:hover:bg-gray-800/70'
}`} }`}
> >
@ -257,7 +257,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({ onBack, onComplete, ba
{/* Taksit Seçenekleri */} {/* Taksit Seçenekleri */}
{selectedPaymentMethod === defaultPaymentMethod && ( {selectedPaymentMethod === defaultPaymentMethod && (
<div className="bg-white rounded-xl shadow border p-4 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40"> <div className="bg-white rounded-xl shadow-sm border p-4 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40">
<h3 className="text-md font-medium text-gray-800 dark:text-gray-100 mb-2"> <h3 className="text-md font-medium text-gray-800 dark:text-gray-100 mb-2">
{translate('::App.Orders.InstallmentOptions')} {translate('::App.Orders.InstallmentOptions')}
</h3> </h3>
@ -309,7 +309,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({ onBack, onComplete, ba
<div className="w-full lg:w-1/3 flex flex-col gap-6"> <div className="w-full lg:w-1/3 flex flex-col gap-6">
{/* Kart Bilgileri */} {/* Kart Bilgileri */}
{selectedPaymentMethod === defaultPaymentMethod && ( {selectedPaymentMethod === defaultPaymentMethod && (
<div className="bg-white rounded-xl shadow border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40 space-y-3"> <div className="bg-white rounded-xl shadow-sm border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40 space-y-3">
<h3 className="text-md font-medium text-gray-800 dark:text-gray-100 mb-3"> <h3 className="text-md font-medium text-gray-800 dark:text-gray-100 mb-3">
{translate('::App.PaymentCard.CardTitle')} {translate('::App.PaymentCard.CardTitle')}
</h3> </h3>
@ -358,7 +358,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({ onBack, onComplete, ba
)} )}
{/* Sipariş Özeti ve Butonlar */} {/* Sipariş Özeti ve Butonlar */}
<div className="bg-white rounded-xl shadow border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40"> <div className="bg-white rounded-xl shadow-sm border p-6 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40">
<h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4"> <h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
{translate('::App.PaymentSummary.SummaryTitle')} {translate('::App.PaymentSummary.SummaryTitle')}
</h3> </h3>

View file

@ -96,7 +96,7 @@ export const ProductCard: React.FC<ProductCardProps> = ({
} }
return ( return (
<div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden hover:shadow-lg transition-all duration-300 group flex flex-col h-full dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40"> <div className="bg-white rounded-xl shadow-xs border border-gray-200 overflow-hidden hover:shadow-lg transition-all duration-300 group flex flex-col h-full dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40">
{product.imageUrl && ( {product.imageUrl && (
<div className="aspect-video overflow-hidden"> <div className="aspect-video overflow-hidden">
<img <img

View file

@ -88,8 +88,8 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
return ( return (
<div className="flex flex-col lg:flex-row gap-8"> <div className="flex flex-col lg:flex-row gap-8">
<aside className="lg:w-64 flex-shrink-0"> <aside className="lg:w-64 shrink-0">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-2 sticky top-40 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40"> <div className="bg-white rounded-lg shadow-xs border border-gray-200 p-2 sticky top-40 dark:border-gray-700 dark:bg-gray-900 dark:shadow-gray-950/40">
<div className="flex items-center space-x-2 mb-4"> <div className="flex items-center space-x-2 mb-4">
<FaFilter className="w-5 h-5 text-gray-600 dark:text-gray-300" /> <FaFilter className="w-5 h-5 text-gray-600 dark:text-gray-300" />
<h3 className="font-semibold text-gray-900 dark:text-gray-100"> <h3 className="font-semibold text-gray-900 dark:text-gray-100">

View file

@ -566,7 +566,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<Button <Button
onClick={() => handleCustomerTypeChange(true)} onClick={() => handleCustomerTypeChange(true)}
variant="plain" variant="plain"
className={`relative block h-auto w-full p-4 border-2 rounded-xl transition-all text-left select-none shadow-sm ${ className={`relative block h-auto w-full p-4 border-2 rounded-xl transition-all text-left select-none shadow-xs ${
isExisting === true isExisting === true
? 'border-blue-600 bg-blue-100 shadow-lg ring-4 ring-blue-200 scale-[1.02] dark:border-sky-400 dark:bg-sky-950/60 dark:ring-sky-500/30' ? 'border-blue-600 bg-blue-100 shadow-lg ring-4 ring-blue-200 scale-[1.02] dark:border-sky-400 dark:bg-sky-950/60 dark:ring-sky-500/30'
: 'border-gray-200 bg-white hover:border-blue-400 hover:bg-blue-50/60 dark:border-gray-700 dark:bg-gray-800/70 dark:hover:border-sky-500 dark:hover:bg-sky-950/30' : 'border-gray-200 bg-white hover:border-blue-400 hover:bg-blue-50/60 dark:border-gray-700 dark:bg-gray-800/70 dark:hover:border-sky-500 dark:hover:bg-sky-950/30'
@ -586,7 +586,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
<Button <Button
onClick={() => handleCustomerTypeChange(false)} onClick={() => handleCustomerTypeChange(false)}
variant="plain" variant="plain"
className={`relative block h-auto w-full p-4 border-2 rounded-xl transition-all text-left select-none shadow-sm ${ className={`relative block h-auto w-full p-4 border-2 rounded-xl transition-all text-left select-none shadow-xs ${
isExisting === false isExisting === false
? 'border-blue-600 bg-blue-100 shadow-lg ring-4 ring-blue-200 scale-[1.02] dark:border-sky-400 dark:bg-sky-950/60 dark:ring-sky-500/30' ? 'border-blue-600 bg-blue-100 shadow-lg ring-4 ring-blue-200 scale-[1.02] dark:border-sky-400 dark:bg-sky-950/60 dark:ring-sky-500/30'
: 'border-gray-200 bg-white hover:border-blue-400 hover:bg-blue-50/60 dark:border-gray-700 dark:bg-gray-800/70 dark:hover:border-sky-500 dark:hover:bg-sky-950/30' : 'border-gray-200 bg-white hover:border-blue-400 hover:bg-blue-50/60 dark:border-gray-700 dark:bg-gray-800/70 dark:hover:border-sky-500 dark:hover:bg-sky-950/30'
@ -641,7 +641,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
icon={<FaSearch className="w-4 h-4" />} icon={<FaSearch className="w-4 h-4" />}
variant="solid" variant="solid"
size="sm" size="sm"
className="!h-[40px] min-w-[180px] sm:mr-2 sm:rounded-r-lg sm:rounded-l-none [&>span]:gap-2" className="h-[40px]! min-w-[180px] sm:mr-2 sm:rounded-r-lg sm:rounded-l-none [&>span]:gap-2"
> >
{isLoadingTenant {isLoadingTenant
? translate('::App.Tenant.Searching') ? translate('::App.Tenant.Searching')

View file

@ -86,8 +86,8 @@ interface PublicThemeToggleProps {
export const PublicThemeToggle = ({ export const PublicThemeToggle = ({
className = 'inline-flex h-9 items-center rounded-lg p-0.5', className = 'inline-flex h-9 items-center rounded-lg p-0.5',
buttonClassName = '!h-8 !w-8 xl:!w-auto !px-0 xl:!px-2.5 !border-transparent !shadow-none !bg-transparent !text-gray-300 hover:!bg-transparent hover:!text-white', buttonClassName = 'h-8! w-8! xl:w-auto! px-0! xl:px-2.5! border-transparent! shadow-none! bg-transparent! text-gray-300! hover:bg-transparent! hover:text-white!',
activeClassName = '!bg-white !text-gray-950', activeClassName = 'bg-white! text-gray-950!',
iconSize = 15, iconSize = 15,
}: PublicThemeToggleProps) => { }: PublicThemeToggleProps) => {
const [isDarkMode, setThemeMode] = useDarkMode() const [isDarkMode, setThemeMode] = useDarkMode()
@ -99,14 +99,14 @@ export const PublicThemeToggle = ({
active: !isDarkMode, active: !isDarkMode,
title: '::App.Theme.LightMode', title: '::App.Theme.LightMode',
icon: <LuSun size={iconSize} strokeWidth={1.8} />, icon: <LuSun size={iconSize} strokeWidth={1.8} />,
shape: '!rounded-l-md !rounded-r-none', shape: 'rounded-l-md! rounded-r-none!',
}, },
{ {
mode: THEME_ENUM.MODE_DARK, mode: THEME_ENUM.MODE_DARK,
active: isDarkMode, active: isDarkMode,
title: '::App.Theme.DarkMode', title: '::App.Theme.DarkMode',
icon: <LuMoon size={iconSize} strokeWidth={1.8} />, icon: <LuMoon size={iconSize} strokeWidth={1.8} />,
shape: '!rounded-r-md !rounded-l-none', shape: 'rounded-r-md! rounded-l-none!',
}, },
] ]
@ -138,7 +138,7 @@ export const PublicDemoButton = ({ className = '' }: { className?: string }) =>
return ( return (
<Button <Button
className={`group !h-9 !w-9 !overflow-visible !bg-transparent !px-0 !text-gray-200 !shadow-none transition-colors hover:!bg-transparent hover:!text-white ${className}`} className={`group h-9! w-9! overflow-visible! bg-transparent! px-0! text-gray-200! shadow-none! transition-colors hover:bg-transparent! hover:text-white! ${className}`}
size="sm" size="sm"
type="button" type="button"
variant="plain" variant="plain"
@ -147,9 +147,9 @@ export const PublicDemoButton = ({ className = '' }: { className?: string }) =>
closeMobileMenu?.() closeMobileMenu?.()
}} }}
> >
<span className="relative inline-flex h-7 w-7 items-center justify-center overflow-visible rounded-full border-2 border-stone-700 bg-gradient-to-b from-red-400 via-red-600 to-red-800 shadow-[inset_0_-3px_6px_rgba(0,0,0,0.35),0_1px_3px_rgba(0,0,0,0.35)] ring-1 ring-black/60 transition-all duration-200 group-hover:scale-105 group-hover:from-red-300 group-hover:via-red-500 group-hover:to-red-700 group-hover:shadow-[inset_0_-3px_6px_rgba(0,0,0,0.3),0_2px_8px_rgba(239,68,68,0.35)]"> <span className="relative inline-flex h-7 w-7 items-center justify-center overflow-visible rounded-full border-2 border-stone-700 bg-linear-to-b from-red-400 via-red-600 to-red-800 shadow-[inset_0_-3px_6px_rgba(0,0,0,0.35),0_1px_3px_rgba(0,0,0,0.35)] ring-1 ring-black/60 transition-all duration-200 group-hover:scale-105 group-hover:from-red-300 group-hover:via-red-500 group-hover:to-red-700 group-hover:shadow-[inset_0_-3px_6px_rgba(0,0,0,0.3),0_2px_8px_rgba(239,68,68,0.35)]">
<span className="absolute inset-x-1 top-1 h-2 rounded-full bg-white/35 blur-[1px] transition-colors group-hover:bg-white/50" /> <span className="absolute inset-x-1 top-1 h-2 rounded-full bg-white/35 blur-[1px] transition-colors group-hover:bg-white/50" />
<span className="absolute left-1/2 top-1/2 z-10 w-12 -translate-x-1/2 -translate-y-1/2 text-center uppercase leading-none tracking-tight text-white drop-shadow"> <span className="absolute left-1/2 top-1/2 z-10 w-12 -translate-x-1/2 -translate-y-1/2 text-center uppercase leading-none tracking-tight text-white drop-shadow-sm">
{translate('::App.Demos')} {translate('::App.Demos')}
</span> </span>
</span> </span>
@ -276,7 +276,7 @@ export const PublicNav = ({
return ( return (
<div key={item.code} className="group/menu relative"> <div key={item.code} className="group/menu relative">
{renderItem(item)} {renderItem(item)}
<div className="invisible absolute left-0 top-full z-20 min-w-[13rem] rounded-lg border border-white/10 bg-gray-950/98 py-2 opacity-0 shadow-xl backdrop-blur-md transition-all duration-150 group-hover/menu:visible group-hover/menu:opacity-100"> <div className="invisible absolute left-0 top-full z-20 min-w-52 rounded-lg border border-white/10 bg-gray-950/98 py-2 opacity-0 shadow-xl backdrop-blur-md transition-all duration-150 group-hover/menu:visible group-hover/menu:opacity-100">
{item.children.map((child) => renderItem(child, 'px-4 py-2'))} {item.children.map((child) => renderItem(child, 'px-4 py-2'))}
</div> </div>
</div> </div>

View file

@ -41,10 +41,10 @@ export type ScriptBuilderDialogProps = {
} }
const controlClass = const controlClass =
'w-full min-w-0 h-8 px-2 rounded border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 text-sm text-gray-700 dark:text-gray-100 focus:outline-none focus:border-indigo-400' 'w-full min-w-0 h-8 px-2 rounded-sm border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 text-sm text-gray-700 dark:text-gray-100 focus:outline-hidden focus:border-indigo-400'
const cardClass = const cardClass =
'rounded-lg border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-900' 'rounded-lg border border-gray-200 bg-white shadow-xs dark:border-gray-700 dark:bg-gray-900'
const editorOptions = { const editorOptions = {
automaticLayout: true, automaticLayout: true,
@ -427,7 +427,7 @@ function ScriptBuilderDialog({
})) }))
/** Ayar satirindaki her alan ayni yukseklikte, dar panelde alt satira sarar. */ /** Ayar satirindaki her alan ayni yukseklikte, dar panelde alt satira sarar. */
const fieldClass = 'min-w-0 basis-[9.5rem] grow' const fieldClass = 'min-w-0 basis-38 grow'
const fieldLabel = (text: string, title?: string) => ( const fieldLabel = (text: string, title?: string) => (
<span className="mb-1 block truncate text-xs text-gray-500" title={title}> <span className="mb-1 block truncate text-xs text-gray-500" title={title}>
@ -446,7 +446,7 @@ function ScriptBuilderDialog({
return ( return (
<Fragment key={index}> <Fragment key={index}>
{index > 0 ? ( {index > 0 ? (
<label className="min-w-0 basis-[6.5rem] grow-0"> <label className="min-w-0 basis-26 grow-0">
{fieldLabel(translate('::App.ScriptBuilder.Conjunction'))} {fieldLabel(translate('::App.ScriptBuilder.Conjunction'))}
<Select <Select
size="sm" size="sm"
@ -574,14 +574,14 @@ function ScriptBuilderDialog({
</div> </div>
</div> </div>
{conditions.length > 1 && ( {conditions.length > 1 && (
<span className="shrink-0 rounded-full bg-violet-100 px-2 py-[1px] text-[11px] text-violet-700 dark:bg-violet-900 dark:text-violet-200"> <span className="shrink-0 rounded-full bg-violet-100 px-2 py-px text-[11px] text-violet-700 dark:bg-violet-900 dark:text-violet-200">
{translate('::App.ScriptBuilder.ConditionCount', { count: conditions.length })} ·{' '} {translate('::App.ScriptBuilder.ConditionCount', { count: conditions.length })} ·{' '}
{translate(rule.join === 'or' ? '::App.Platform.Or' : '::App.Platform.And')} {translate(rule.join === 'or' ? '::App.Platform.Or' : '::App.Platform.And')}
</span> </span>
)} )}
{triggerInfo && trigger !== dialect.triggers?.[0]?.value && ( {triggerInfo && trigger !== dialect.triggers?.[0]?.value && (
<span <span
className="shrink-0 rounded-full bg-sky-100 px-2 py-[1px] text-[11px] text-sky-700 dark:bg-sky-900 dark:text-sky-200" className="shrink-0 rounded-full bg-sky-100 px-2 py-px text-[11px] text-sky-700 dark:bg-sky-900 dark:text-sky-200"
title={triggerInfo.help} title={triggerInfo.help}
> >
{triggerInfo.label} {triggerInfo.label}
@ -589,7 +589,7 @@ function ScriptBuilderDialog({
)} )}
{!complete && ( {!complete && (
<span <span
className="flex shrink-0 items-center gap-1 rounded-full bg-amber-100 px-2 py-[1px] text-[11px] text-amber-700 dark:bg-amber-900 dark:text-amber-200" className="flex shrink-0 items-center gap-1 rounded-full bg-amber-100 px-2 py-px text-[11px] text-amber-700 dark:bg-amber-900 dark:text-amber-200"
title={ title={
dialect.getRuleWarning?.(rule) || dialect.getRuleWarning?.(rule) ||
translate('::App.ScriptBuilder.IncompleteRuleWarning') translate('::App.ScriptBuilder.IncompleteRuleWarning')
@ -671,7 +671,7 @@ function ScriptBuilderDialog({
{recipe.params.map((param) => renderParam(rule, param))} {recipe.params.map((param) => renderParam(rule, param))}
</div> </div>
<pre className="mt-3 overflow-x-auto rounded border border-gray-100 bg-gray-950 px-3 py-2 font-mono text-[11px] text-emerald-100 dark:border-gray-800"> <pre className="mt-3 overflow-x-auto rounded-sm border border-gray-100 bg-gray-950 px-3 py-2 font-mono text-[11px] text-emerald-100 dark:border-gray-800">
{dialect.buildRuleLine(rule, rules) || recipe.example} {dialect.buildRuleLine(rule, rules) || recipe.example}
</pre> </pre>
</div> </div>
@ -686,7 +686,7 @@ function ScriptBuilderDialog({
<FaSearch className="text-gray-400" size={11} /> <FaSearch className="text-gray-400" size={11} />
<Input <Input
unstyle unstyle
className="w-full min-w-0 bg-transparent text-xs text-gray-700 outline-none dark:text-gray-100" className="w-full min-w-0 bg-transparent text-xs text-gray-700 outline-hidden dark:text-gray-100"
placeholder={translate('::App.ScriptBuilder.SearchHelp')} placeholder={translate('::App.ScriptBuilder.SearchHelp')}
value={helpSearch} value={helpSearch}
onChange={(event) => setHelpSearch(event.target.value)} onChange={(event) => setHelpSearch(event.target.value)}
@ -710,7 +710,7 @@ function ScriptBuilderDialog({
<button <button
key={snippet.label} key={snippet.label}
type="button" type="button"
className="rounded border border-gray-100 px-2 py-1.5 text-left hover:border-indigo-300 hover:bg-indigo-50 dark:border-gray-800 dark:hover:bg-gray-800" className="rounded-sm border border-gray-100 px-2 py-1.5 text-left hover:border-indigo-300 hover:bg-indigo-50 dark:border-gray-800 dark:hover:bg-gray-800"
title={`${snippet.description}\n\n${snippet.code}`} title={`${snippet.description}\n\n${snippet.code}`}
onClick={() => insertAtCursor(editorRef.current, snippet.code)} onClick={() => insertAtCursor(editorRef.current, snippet.code)}
> >
@ -734,7 +734,7 @@ function ScriptBuilderDialog({
<button <button
key={entry.signature} key={entry.signature}
type="button" type="button"
className="rounded px-1 py-1 text-left hover:bg-indigo-50 dark:hover:bg-gray-800" className="rounded-sm px-1 py-1 text-left hover:bg-indigo-50 dark:hover:bg-gray-800"
title={entry.description} title={entry.description}
onClick={() => insertAtCursor(editorRef.current, apiEntryName(entry))} onClick={() => insertAtCursor(editorRef.current, apiEntryName(entry))}
> >
@ -767,10 +767,10 @@ function ScriptBuilderDialog({
{/* {/*
Yükseklik zinciri iki yerden kopuyordu: Dialog'un `height` prop'u yalnızca Yükseklik zinciri iki yerden kopuyordu: Dialog'un `height` prop'u yalnızca
react-modal içeriğine uygulanıyor, ve `.dialog-body` global olarak `flex-1` react-modal içeriğine uygulanıyor, ve `.dialog-body` global olarak `flex-1`
alıyor. `!flex-none` ile flex boyutlandırmasını kapatıp yüksekliği alıyor. `flex-none!` ile flex boyutlandırmasını kapatıp yüksekliği
doğrudan veriyoruz. doğrudan veriyoruz.
*/} */}
<Dialog.Body className="flex h-[calc(100vh-16rem)] max-h-[calc(90vh-7rem)] min-h-[320px] !flex-none flex-col gap-3 !overflow-hidden mt-5"> <Dialog.Body className="flex h-[calc(100vh-16rem)] max-h-[calc(90vh-7rem)] min-h-[320px] flex-none! flex-col gap-3 overflow-hidden! mt-5">
<div className="flex flex-wrap items-center gap-2 border-b border-gray-200 pb-3 dark:border-gray-700"> <div className="flex flex-wrap items-center gap-2 border-b border-gray-200 pb-3 dark:border-gray-700">
<FaCode className="text-indigo-500" /> <FaCode className="text-indigo-500" />
<h5 className="mr-1">{dialect.title}</h5> <h5 className="mr-1">{dialect.title}</h5>

View file

@ -34,10 +34,10 @@ const AdaptableCard = (props: AdaptableCardProps) => {
type === LAYOUT_TYPE_MODERN && 'border-0', type === LAYOUT_TYPE_MODERN && 'border-0',
type === LAYOUT_TYPE_MODERN && type === LAYOUT_TYPE_MODERN &&
rightSideBorder && rightSideBorder &&
'ltr:border-r-0 rtl:border-l-0 ltr:md:border-r rtl:md:border-l md:border-gray-200 md:dark:border-gray-600 rounded-tr-none rounded-br-none rtl:rounded-tr-none rtl:rounded-br-none', 'ltr:border-r-0 rtl:border-l-0 md:ltr:border-r md:rtl:border-l md:border-gray-200 md:dark:border-gray-600 rounded-tr-none rounded-br-none rtl:rounded-tr-none rtl:rounded-br-none',
type === LAYOUT_TYPE_MODERN && type === LAYOUT_TYPE_MODERN &&
leftSideBorder && leftSideBorder &&
'ltr:border-l-0 rtl:border-r-0 ltr:md:border-l rtl:md:border-r md:border-gray-200 md:dark:border-gray-600 rounded-tl-none rounded-bl-none rtl:rounded-tl-none rtl:rounded-bl-none', 'ltr:border-l-0 rtl:border-r-0 md:ltr:border-l md:rtl:border-r md:border-gray-200 md:dark:border-gray-600 rounded-tl-none rounded-bl-none rtl:rounded-tl-none rtl:rounded-bl-none',
type === LAYOUT_TYPE_MODERN && type === LAYOUT_TYPE_MODERN &&
divider && divider &&
`${ `${

View file

@ -89,7 +89,7 @@ const BarcodeScannerDialog = ({
<p className="mb-1 text-sm font-semibold"> <p className="mb-1 text-sm font-semibold">
{translate('::App.BarcodeScanner.ScannedCount')}: {scanned.length} {translate('::App.BarcodeScanner.ScannedCount')}: {scanned.length}
</p> </p>
<ul className="max-h-32 overflow-auto rounded border text-sm"> <ul className="max-h-32 overflow-auto rounded-sm border text-sm">
{scanned.map((code, index) => ( {scanned.map((code, index) => (
<li key={`${code}-${index}`} className="border-b px-2 py-1 last:border-b-0"> <li key={`${code}-${index}`} className="border-b px-2 py-1 last:border-b-0">
{code} {code}

View file

@ -64,7 +64,7 @@ const BarcodeViewer = ({
// kaçışlanarak yazılır, bu yüzden gömmek güvenlidir. // kaçışlanarak yazılır, bu yüzden gömmek güvenlidir.
dangerouslySetInnerHTML={{ __html: svg }} dangerouslySetInnerHTML={{ __html: svg }}
className={classNames( className={classNames(
'inline-block rounded bg-white p-2', 'inline-block rounded-sm bg-white p-2',
fitWidth && 'block w-full [&>svg]:h-auto [&>svg]:w-full', fitWidth && 'block w-full [&>svg]:h-auto [&>svg]:w-full',
)} )}
/> />

View file

@ -1,306 +0,0 @@
import type { CheckboxProps } from '@/components/ui/Checkbox'
import Checkbox from '@/components/ui/Checkbox'
import Pagination from '@/components/ui/Pagination'
import Select from '@/components/ui/Select'
import type { SkeletonProps } from '@/components/ui/Skeleton'
import Table from '@/components/ui/Table'
import {
CellContext,
ColumnDef,
ColumnSort,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
Row,
useReactTable,
} from '@tanstack/react-table'
import classNames from 'classnames'
import type { ChangeEvent, ForwardedRef } from 'react'
import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
import TableRowSkeleton from './loaders/TableRowSkeleton'
import Loading from './Loading'
export type OnSortParam = { order: 'asc' | 'desc' | ''; key: string | number }
type DataTableProps<T> = {
columns: ColumnDef<T>[]
data?: unknown[]
loading?: boolean
onCheckBoxChange?: (checked: boolean, row: T) => void
onIndeterminateCheckBoxChange?: (checked: boolean, rows: Row<T>[]) => void
onPaginationChange?: (page: number) => void
onSelectChange?: (num: number) => void
onSort?: (sort: OnSortParam) => void
pageSizes?: number[]
selectable?: boolean
skeletonAvatarColumns?: number[]
skeletonAvatarProps?: SkeletonProps
pagingData?: {
total: number
pageIndex: number
pageSize: number
}
}
type CheckBoxChangeEvent = ChangeEvent<HTMLInputElement>
interface IndeterminateCheckboxProps extends Omit<CheckboxProps, 'onChange'> {
onChange: (event: CheckBoxChangeEvent) => void
indeterminate: boolean
onCheckBoxChange?: (event: CheckBoxChangeEvent) => void
onIndeterminateCheckBoxChange?: (event: CheckBoxChangeEvent) => void
}
const { Tr, Th, Td, THead, TBody, Sorter } = Table
const IndeterminateCheckbox = (props: IndeterminateCheckboxProps) => {
const { indeterminate, onChange, onCheckBoxChange, onIndeterminateCheckBoxChange, ...rest } =
props
const ref = useRef<HTMLInputElement>(null)
useEffect(() => {
if (typeof indeterminate === 'boolean' && ref.current) {
ref.current.indeterminate = !rest.checked && indeterminate
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref, indeterminate])
const handleChange = (e: CheckBoxChangeEvent) => {
onChange(e)
onCheckBoxChange?.(e)
onIndeterminateCheckBoxChange?.(e)
}
return <Checkbox ref={ref} className="mb-0" onChange={(_, e) => handleChange(e)} {...rest} />
}
export type DataTableResetHandle = {
resetSorting: () => void
resetSelected: () => void
}
function DataTableBase<T>(props: DataTableProps<T>, ref: ForwardedRef<DataTableResetHandle>) {
const {
skeletonAvatarColumns,
columns: columnsProp = [],
data = [],
loading = false,
onCheckBoxChange,
onIndeterminateCheckBoxChange,
onPaginationChange,
onSelectChange,
onSort,
pageSizes = [10, 25, 50, 100],
selectable = false,
skeletonAvatarProps,
pagingData = {
total: 0,
pageIndex: 1,
pageSize: 10,
},
} = props
const { pageSize, pageIndex, total } = pagingData
const [sorting, setSorting] = useState<ColumnSort[] | null>(null)
const pageSizeOption = useMemo(
() =>
pageSizes.map((number) => ({
value: number,
label: `${number} / page`,
})),
[pageSizes],
)
const handleCheckBoxChange = (checked: boolean, row: T) => {
if (!loading) {
onCheckBoxChange?.(checked, row)
}
}
const handleIndeterminateCheckBoxChange = (checked: boolean, rows: Row<T>[]) => {
if (!loading) {
onIndeterminateCheckBoxChange?.(checked, rows)
}
}
const handlePaginationChange = (page: number) => {
if (!loading) {
onPaginationChange?.(page)
}
}
const handleSelectChange = (value?: number) => {
if (!loading) {
onSelectChange?.(Number(value))
}
}
useEffect(() => {
if (Array.isArray(sorting)) {
const sortOrder = sorting.length > 0 ? (sorting[0].desc ? 'desc' : 'asc') : ''
const id = sorting.length > 0 ? sorting[0].id : ''
onSort?.({ order: sortOrder, key: id })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sorting])
const finalColumns: ColumnDef<T>[] = useMemo(() => {
const columns = columnsProp
if (selectable) {
return [
{
id: 'select',
header: ({ table }) => (
<IndeterminateCheckbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
onIndeterminateCheckBoxChange={(e) => {
handleIndeterminateCheckBoxChange(e.target.checked, table.getRowModel().rows)
}}
/>
),
cell: ({ row }) => (
<IndeterminateCheckbox
checked={row.getIsSelected()}
disabled={!row.getCanSelect()}
indeterminate={row.getIsSomeSelected()}
onChange={row.getToggleSelectedHandler()}
onCheckBoxChange={(e) => handleCheckBoxChange(e.target.checked, row.original)}
/>
),
},
...columns,
]
}
return columns
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [columnsProp, selectable])
const table = useReactTable({
data,
columns: finalColumns as ColumnDef<unknown | object | any[], any>[],
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
manualPagination: true,
manualSorting: true,
onSortingChange: (sorter) => {
setSorting(sorter as ColumnSort[])
},
// Satir secimi tablonun kendi durumunda tutulur. Disaridan kontrol edilen bir
// `rowSelection` degeri `onRowSelectionChange` olmadan degisimi yutuyor, onay kutusu
// hicbir zaman isaretlenmiyordu; secilen satirlari cagiran taraf `onCheckBoxChange`
// ile zaten kendi durumunda biriktiriyor.
state: {
sorting: sorting as ColumnSort[],
},
})
const resetSorting = () => {
table.resetSorting()
}
const resetSelected = () => {
table.toggleAllRowsSelected(false)
}
useImperativeHandle(ref, () => ({
resetSorting,
resetSelected,
}))
return (
<Loading loading={loading && data.length !== 0} type="cover">
<Table>
<THead>
{table.getHeaderGroups().map((headerGroup) => (
<Tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<Th key={header.id} colSpan={header.colSpan}>
{header.isPlaceholder ? null : (
<div
className={classNames(
header.column.getCanSort() && 'cursor-pointer select-none point',
loading && 'pointer-events-none',
)}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{header.column.getCanSort() && (
<Sorter sort={header.column.getIsSorted()} />
)}
</div>
)}
</Th>
)
})}
</Tr>
))}
</THead>
{loading && data.length === 0 ? (
<TableRowSkeleton
columns={(finalColumns as Array<T>).length}
rows={pagingData.pageSize}
avatarInColumns={skeletonAvatarColumns}
avatarProps={skeletonAvatarProps}
/>
) : (
<TBody>
{table
.getRowModel()
.rows.slice(0, pageSize)
.map((row) => {
return (
<Tr key={row.id}>
{row.getVisibleCells().map((cell) => {
return (
<Td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Td>
)
})}
</Tr>
)
})}
</TBody>
)}
</Table>
<div className="flex items-center justify-between mt-4">
<Pagination
pageSize={pageSize}
currentPage={pageIndex}
total={total}
onChange={handlePaginationChange}
/>
<div style={{ minWidth: 130 }}>
<Select
size="sm"
menuPlacement="top"
isSearchable={false}
value={pageSizeOption.filter((option) => option.value === pageSize)}
options={pageSizeOption}
onChange={(option) => handleSelectChange(option?.value)}
/>
</div>
</div>
</Loading>
)
}
const DataTable = forwardRef(DataTableBase) as <T>(
props: DataTableProps<T> & {
ref?: ForwardedRef<DataTableResetHandle>
},
) => ReturnType<typeof DataTableBase>
export type { CellContext, ColumnDef, Row }
export default DataTable

View file

@ -46,7 +46,7 @@ function DbMigrateLogPanel({ title, onClose }: DbMigrateLogPanelProps) {
}, [logs]) }, [logs])
return ( return (
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/60"> <div className="fixed inset-0 z-9999 flex items-center justify-center bg-black/60">
<div className="flex flex-col w-[900px] max-w-[95vw] h-[520px] max-h-[90vh] rounded-xl shadow-2xl bg-gray-900 border border-gray-700"> <div className="flex flex-col w-[900px] max-w-[95vw] h-[520px] max-h-[90vh] rounded-xl shadow-2xl bg-gray-900 border border-gray-700">
<div className="flex items-center justify-between px-4 py-3 border-b border-gray-700"> <div className="flex items-center justify-between px-4 py-3 border-b border-gray-700">
<span className="text-white font-semibold text-sm">{title}</span> <span className="text-white font-semibold text-sm">{title}</span>
@ -59,7 +59,7 @@ function DbMigrateLogPanel({ title, onClose }: DbMigrateLogPanelProps) {
<Button <Button
variant="default" variant="default"
size="xs" size="xs"
className="!bg-gray-800 !border-gray-600 !text-gray-300 hover:!bg-gray-700 hover:!border-gray-400 hover:!text-white" className="bg-gray-800! border-gray-600! text-gray-300! hover:bg-gray-700! hover:border-gray-400! hover:text-white!"
onClick={onClose} onClick={onClose}
> >
Close Close
@ -68,7 +68,7 @@ function DbMigrateLogPanel({ title, onClose }: DbMigrateLogPanelProps) {
</div> </div>
<div className="flex-1 overflow-y-auto p-3 font-mono text-xs leading-relaxed"> <div className="flex-1 overflow-y-auto p-3 font-mono text-xs leading-relaxed">
{logs.map((log, i) => ( {logs.map((log, i) => (
<div key={i} className={`whitespace-pre-wrap break-words ${levelColor(log.level)}`}> <div key={i} className={`whitespace-pre-wrap wrap-break-word ${levelColor(log.level)}`}>
<span className="text-gray-500 mr-2 select-none">{String(i + 1).padStart(4, '0')}</span> <span className="text-gray-500 mr-2 select-none">{String(i + 1).padStart(4, '0')}</span>
{log.message} {log.message}
</div> </div>

View file

@ -56,7 +56,7 @@ const CoveredLoading = (props: BaseLoadingProps) => {
<Component className={classNames(loading ? 'relative' : '', className)}> <Component className={classNames(loading ? 'relative' : '', className)}>
{children} {children}
{loading && ( {loading && (
<div className="w-full h-full bg-white dark:bg-gray-800 dark:bg-opacity-60 bg-opacity-50 absolute inset-0" /> <div className="w-full h-full bg-white/50 dark:bg-gray-800/60 absolute inset-0" />
)} )}
{loading && ( {loading && (
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10"> <div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10">

View file

@ -30,7 +30,7 @@ const withCode = (text: string, keyPrefix: string): ReactNode[] =>
const rest = part.slice(trimmed.length) const rest = part.slice(trimmed.length)
return ( return (
<Fragment key={`${keyPrefix}-c${index}`}> <Fragment key={`${keyPrefix}-c${index}`}>
<code className="rounded bg-gray-100 px-1 py-0.5 font-mono text-[0.9em] text-gray-800 dark:bg-gray-700 dark:text-gray-100"> <code className="rounded-sm bg-gray-100 px-1 py-0.5 font-mono text-[0.9em] text-gray-800 dark:bg-gray-700 dark:text-gray-100">
{trimmed} {trimmed}
</code> </code>
{rest} {rest}

View file

@ -6,14 +6,11 @@ export { default as BarcodeViewer } from './BarcodeViewer'
export { default as PermissionCheck } from './PermissionCheck' export { default as PermissionCheck } from './PermissionCheck'
export { default as ConfirmDialog } from './ConfirmDialog' export { default as ConfirmDialog } from './ConfirmDialog'
export { default as Container } from './Container' export { default as Container } from './Container'
export { default as DataTable } from './DataTable'
export { default as DoubleSidedImage } from './DoubleSidedImage' export { default as DoubleSidedImage } from './DoubleSidedImage'
export { default as Loading } from './Loading' export { default as Loading } from './Loading'
export { default as NavToggle } from './NavToggle' export { default as NavToggle } from './NavToggle'
export { default as PasswordInput } from './PasswordInput' export { default as PasswordInput } from './PasswordInput'
export { default as RichText } from './RichText' export { default as RichText } from './RichText'
export { default as SegmentItemOption } from './SegmentItemOption' export { default as SegmentItemOption } from './SegmentItemOption'
export { default as TableRowSkeleton } from './loaders/TableRowSkeleton'
export { default as TenantSelector } from './TenantSelector' export { default as TenantSelector } from './TenantSelector'
export type { DataTableResetHandle, OnSortParam, ColumnDef, Row, CellContext } from './DataTable'

View file

@ -1,44 +0,0 @@
import Skeleton from '@/components/ui/Skeleton'
import Table from '@/components/ui/Table'
import type { SkeletonProps } from '@/components/ui/Skeleton'
type TableRowSkeletonProps = {
columns?: number
rows?: number
avatarInColumns?: number[]
avatarProps?: SkeletonProps
}
const { Tr, Td, TBody } = Table
const TableRowSkeleton = (props: TableRowSkeletonProps) => {
const { columns = 1, rows = 10, avatarInColumns = [], avatarProps } = props
return (
<TBody>
{Array.from(new Array(rows), (_, i) => i + 0).map((row) => (
<Tr key={`row-${row}`}>
{Array.from(new Array(columns), (_, i) => i + 0).map(
(col) => (
<Td key={`col-${col}`}>
<div className="flex flex-auto items-center gap-2">
{avatarInColumns.includes(col) && (
<div>
<Skeleton
variant="circle"
{...avatarProps}
/>
</div>
)}
<Skeleton />
</div>
</Td>
)
)}
</Tr>
))}
</TBody>
)
}
export default TableRowSkeleton

View file

@ -50,7 +50,7 @@ const LanguageSelectorBase = ({ className }: CommonProps) => {
} }
return ( return (
<Dropdown renderTitle={selectedLanguage} placement="bottom-start" menuClass="z-[60]"> <Dropdown renderTitle={selectedLanguage} placement="bottom-start" menuClass="z-60">
{languageList?.map((lang) => ( {languageList?.map((lang) => (
<Dropdown.Item <Dropdown.Item
key={lang.cultureName} key={lang.cultureName}

View file

@ -366,7 +366,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
if (!auth.session.signedIn || !location.pathname.startsWith('/admin')) return null if (!auth.session.signedIn || !location.pathname.startsWith('/admin')) return null
const panelClassName = const panelClassName =
'pointer-events-auto fixed inset-2 z-[51] overflow-hidden rounded-xl border border-gray-200 bg-white/80 shadow-[0_24px_80px_rgba(15,23,42,0.35)] backdrop-blur-xl dark:border-gray-700 dark:bg-gray-900/85 sm:inset-4' 'pointer-events-auto fixed inset-2 z-51 overflow-hidden rounded-xl border border-gray-200 bg-white/80 shadow-[0_24px_80px_rgba(15,23,42,0.35)] backdrop-blur-xl dark:border-gray-700 dark:bg-gray-900/85 sm:inset-4'
const headerActionClassName = const headerActionClassName =
'text-gray-600 hover:bg-gray-900/10 hover:text-gray-900 active:bg-gray-900/15 dark:text-gray-200 dark:hover:bg-white/10 dark:hover:text-white dark:active:bg-white/15' 'text-gray-600 hover:bg-gray-900/10 hover:text-gray-900 active:bg-gray-900/15 dark:text-gray-200 dark:hover:bg-white/10 dark:hover:text-white dark:active:bg-white/15'
@ -380,7 +380,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
aria-label={translate('::App.MessengerWidget.Minimize')} aria-label={translate('::App.MessengerWidget.Minimize')}
variant="plain" variant="plain"
shape="none" shape="none"
className="fixed inset-0 z-50 !h-auto cursor-default bg-slate-950/25 !px-0 backdrop-blur-[1px] hover:!bg-slate-950/25 active:!bg-slate-950/25 dark:bg-black/55 dark:hover:!bg-black/55 dark:active:!bg-black/55" className="fixed inset-0 z-50 h-auto! cursor-default bg-slate-950/25 px-0! backdrop-blur-[1px] hover:bg-slate-950/25! active:bg-slate-950/25! dark:bg-black/55 dark:hover:bg-black/55! dark:active:bg-black/55!"
onClick={closeWidget} onClick={closeWidget}
/> />
<div className={panelClassName} role="dialog" aria-modal="true"> <div className={panelClassName} role="dialog" aria-modal="true">
@ -429,7 +429,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
</div> </div>
<div className="flex items-center gap-2 p-3"> <div className="flex items-center gap-2 p-3">
<div className="min-w-0 flex-[6]"> <div className="min-w-0 flex-6">
<Input <Input
size="sm" size="sm"
value={filter} value={filter}
@ -465,7 +465,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
variant="plain" variant="plain"
shape="none" shape="none"
block block
className={`mb-1 !flex !h-auto items-center gap-3 !rounded-md !px-2 !py-2 text-left transition ${ className={`mb-1 !flex h-auto! items-center gap-3 rounded-md! px-2! py-2! text-left transition ${
active active
? 'bg-emerald-50 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-100' ? 'bg-emerald-50 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-100'
: 'hover:bg-white dark:hover:bg-gray-800' : 'hover:bg-white dark:hover:bg-gray-800'
@ -593,7 +593,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
className={`group flex max-w-[76%] items-start gap-1.5 ${own ? 'flex-row-reverse' : ''}`} className={`group flex max-w-[76%] items-start gap-1.5 ${own ? 'flex-row-reverse' : ''}`}
> >
<div <div
className={`rounded-lg px-3 py-2 shadow-sm ${ className={`rounded-lg px-3 py-2 shadow-xs ${
own own
? 'bg-emerald-600 text-white' ? 'bg-emerald-600 text-white'
: 'bg-gray-100 text-gray-900 dark:bg-gray-700 dark:text-gray-100' : 'bg-gray-100 text-gray-900 dark:bg-gray-700 dark:text-gray-100'
@ -660,7 +660,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
variant="plain" variant="plain"
shape="circle" shape="circle"
icon={<FaTrash />} icon={<FaTrash />}
className="mt-1 !h-5 !w-5 shrink-0 !px-0 text-[10px] text-gray-400 opacity-0 transition hover:!bg-red-500 hover:text-white group-hover:opacity-100 focus:opacity-100" className="mt-1 h-5! w-5! shrink-0 px-0! text-[10px] text-gray-400 opacity-0 transition hover:bg-red-500! hover:text-white group-hover:opacity-100 focus:opacity-100"
onClick={() => deleteMessage(message.id)} onClick={() => deleteMessage(message.id)}
/> />
)} )}
@ -685,7 +685,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
variant="plain" variant="plain"
shape="circle" shape="circle"
icon={<FaTrash />} icon={<FaTrash />}
className="!h-5 !w-5 shrink-0 !px-0 text-gray-500 hover:text-red-500" className="h-5! w-5! shrink-0 px-0! text-gray-500 hover:text-red-500"
onClick={() => onClick={() =>
setAttachments((prev) => setAttachments((prev) =>
prev.filter((item) => item.savedFileName !== file.savedFileName), prev.filter((item) => item.savedFileName !== file.savedFileName),
@ -703,9 +703,10 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
<div className="absolute bottom-16 left-2 z-10 sm:left-10"> <div className="absolute bottom-16 left-2 z-10 sm:left-10">
<Suspense fallback={<div className="h-[380px] w-[320px] max-w-[calc(100vw-32px)]" />}> <Suspense fallback={<div className="h-[380px] w-[320px] max-w-[calc(100vw-32px)]" />}>
<EmojiPicker <EmojiPicker
onEmojiClick={onEmojiClick} emojiStyle="apple"
width="min(320px, calc(100vw - 32px))"
height={380} height={380}
width="min(320px, calc(100vw - 32px))"
onEmojiClick={onEmojiClick}
/> />
</Suspense> </Suspense>
</div> </div>
@ -751,7 +752,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
} }
rows={1} rows={1}
disabled={!canSendToSelectedContacts} disabled={!canSendToSelectedContacts}
className="min-h-[36px] flex-1 resize-none border-0 bg-transparent px-2 py-2 text-sm text-gray-900 outline-none placeholder:text-gray-400 focus:ring-0 dark:text-gray-100" className="min-h-[36px] flex-1 resize-none border-0 bg-transparent px-2 py-2 text-sm text-gray-900 outline-hidden placeholder:text-gray-400 focus:ring-0 dark:text-gray-100"
onChange={(event) => setText(event.target.value)} onChange={(event) => setText(event.target.value)}
onKeyDown={(event) => { onKeyDown={(event) => {
if (event.key === 'Enter' && !event.shiftKey) { if (event.key === 'Enter' && !event.shiftKey) {
@ -785,7 +786,7 @@ const MessengerWidgetContent = ({ className }: { className?: string }) => {
className={classNames( className={classNames(
className, className,
textTheme, textTheme,
'pointer-events-auto relative !mx-0 text-2xl transition-colors duration-300 ease-in-out hover:bg-black hover:bg-opacity-5 dark:hover:bg-black dark:hover:bg-opacity-40', 'pointer-events-auto relative mx-0! text-2xl transition-colors duration-300 ease-in-out hover:bg-black/5 dark:hover:bg-black/40',
)} )}
aria-label={translate('::App.MessengerWidget.Title')} aria-label={translate('::App.MessengerWidget.Title')}
role="button" role="button"

View file

@ -55,7 +55,7 @@ type NotificationListItem = {
readed: boolean readed: boolean
} }
const notificationHeight = 'h-[26rem]' const notificationHeight = 'h-104'
/** SignalR duyurusu kaybolursa devreye giren yedek yoklama aralığı. */ /** SignalR duyurusu kaybolursa devreye giren yedek yoklama aralığı. */
const notificationInterval = 300000 // 5 minutes const notificationInterval = 300000 // 5 minutes
const foregroundPollThrottle = 30000 // 30 seconds const foregroundPollThrottle = 30000 // 30 seconds
@ -416,7 +416,7 @@ const NotificationDropdown = ({ className }: { className?: string }) => {
{notificationList.map((item, index) => ( {notificationList.map((item, index) => (
<div <div
key={item.ids[0]} key={item.ids[0]}
className={`relative flex px-4 py-4 cursor-pointer hover:bg-gray-50 active:bg-gray-100 dark:hover:bg-black dark:hover:bg-opacity-20 ${ className={`relative flex px-4 py-4 cursor-pointer hover:bg-gray-50 active:bg-gray-100 dark:hover:bg-black/20 ${
!isLastChild(notificationList, index) !isLastChild(notificationList, index)
? 'border-b border-gray-200 dark:border-gray-600' ? 'border-b border-gray-200 dark:border-gray-600'
: '' : ''

View file

@ -53,7 +53,7 @@ const ListItem = (props: {
<div className="flex items-center"> <div className="flex items-center">
{/* <div {/* <div
className={classNames( className={classNames(
'mr-4 rounded-md ring-1 ring-slate-900/5 shadow-sm text-xl group-hover:shadow h-6 w-6 flex items-center justify-center bg-white dark:bg-gray-700', 'mr-4 rounded-md ring-1 ring-slate-900/5 shadow-xs text-xl group-hover:shadow-sm h-6 w-6 flex items-center justify-center bg-white dark:bg-gray-700',
textTheme, textTheme,
'dark:text-gray-100', 'dark:text-gray-100',
)} )}
@ -193,7 +193,7 @@ const SearchBase = ({ className }: { className?: string }) => {
<Input <Input
unstyle unstyle
ref={inputRef} ref={inputRef}
className="ring-0 outline-none block w-full p-4 text-base bg-transparent text-gray-900 dark:text-gray-100" className="ring-0 outline-hidden block w-full p-4 text-base bg-transparent text-gray-900 dark:text-gray-100"
placeholder={translate('::App.Platform.Search2')} placeholder={translate('::App.Platform.Search2')}
onKeyDown={(e) => e.key === 'Enter' && handleSearch()} onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
/> />

View file

@ -145,7 +145,7 @@ const Alert = forwardRef<HTMLDivElement, AlertProps>((props, ref) => {
{showIcon && <StatusIcon iconColor={typeMap.iconColor} custom={customIcon} type={type} />} {showIcon && <StatusIcon iconColor={typeMap.iconColor} custom={customIcon} type={type} />}
<div <div
className={classNames( className={classNames(
'min-w-0 flex-1 whitespace-normal break-words leading-6', 'min-w-0 flex-1 whitespace-normal wrap-break-word leading-6',
showIcon ? 'ltr:ml-2 rtl:mr-2' : '', showIcon ? 'ltr:ml-2 rtl:mr-2' : '',
)} )}
> >

View file

@ -107,12 +107,12 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
const btn = { const btn = {
bgColor: active bgColor: active
? `bg-${buttonColor}-200 dark:bg-${buttonColor}-50` ? `bg-${buttonColor}-200 dark:bg-${buttonColor}-50`
: `bg-${buttonColor}-50 dark:bg-${buttonColor}-500 dark:bg-opacity-20`, : `bg-${buttonColor}-50 dark:bg-${buttonColor}-500/20`,
textColor: `text-${buttonColor}-${buttonColorLevel} dark:text-${buttonColor}-50`, textColor: `text-${buttonColor}-${buttonColorLevel} dark:text-${buttonColor}-50`,
hoverColor: active hoverColor: active
? '' ? ''
: `hover:bg-${buttonColor}-100 dark:hover:bg-${buttonColor}-500 dark:hover:bg-opacity-30`, : `hover:bg-${buttonColor}-100 dark:hover:bg-${buttonColor}-500/30`,
activeColor: `active:bg-${buttonColor}-200 dark:active:bg-${buttonColor}-500 dark:active:bg-opacity-40`, activeColor: `active:bg-${buttonColor}-200 dark:active:bg-${buttonColor}-500/40`,
} }
return getBtnColor(btn) return getBtnColor(btn)
} }

View file

@ -71,6 +71,7 @@ const Day = forwardRef<HTMLButtonElement, DayProps>((props, ref) => {
} = props } = props
const { themeColor, primaryColorLevel } = useConfig() const { themeColor, primaryColorLevel } = useConfig()
const inRangeOnly = inRange && !disabled && !firstInRange && !lastInRange && !selected
return ( return (
<button <button
@ -78,6 +79,16 @@ const Day = forwardRef<HTMLButtonElement, DayProps>((props, ref) => {
ref={ref} ref={ref}
type="button" type="button"
disabled={disabled} disabled={disabled}
// Aralik gunu tema renginin %10'u: renk adi calisma aninda geldigi icin her renk/ton icin
// ayri `/10` sinifi uretmek yerine temanin renk degiskeni kullanilir.
style={
inRangeOnly
? {
...others.style,
backgroundColor: `color-mix(in oklab, var(--color-${themeColor}-${primaryColorLevel}) 10%, transparent)`,
}
: others.style
}
tabIndex={getDayTabIndex({ tabIndex={getDayTabIndex({
focusable, focusable,
hasValue, hasValue,
@ -102,12 +113,6 @@ const Day = forwardRef<HTMLButtonElement, DayProps>((props, ref) => {
selected && selected &&
!disabled && !disabled &&
`bg-${themeColor}-${primaryColorLevel} text-gray-100`, `bg-${themeColor}-${primaryColorLevel} text-gray-100`,
inRange &&
!disabled &&
!firstInRange &&
!lastInRange &&
!selected &&
`bg-${themeColor}-${primaryColorLevel} bg-opacity-10`,
!inRange && !firstInRange && !lastInRange && 'rounded-lg', !inRange && !firstInRange && !lastInRange && 'rounded-lg',
firstInRange && firstInRange &&
!disabled && !disabled &&

View file

@ -3,7 +3,7 @@ import classNames from 'classnames'
import ReactSelect, { components as ReactSelectComponents } from 'react-select' import ReactSelect, { components as ReactSelectComponents } from 'react-select'
import CreatableSelect from 'react-select/creatable' import CreatableSelect from 'react-select/creatable'
import AsyncSelect from 'react-select/async' import AsyncSelect from 'react-select/async'
import { TW_COLORS, BORDER_RADIUS } from '@/utils/tailwind' import { themeColor as twColor } from '@/utils/tailwind'
import { isEmpty, get } from '@/utils/collection' import { isEmpty, get } from '@/utils/collection'
import { useConfig } from '../ConfigProvider' import { useConfig } from '../ConfigProvider'
import { useForm } from '../Form/context' import { useForm } from '../Form/context'
@ -173,8 +173,6 @@ function SelectBase<
const selectSize = size || inputGroupSize || formControlSize || controlSize const selectSize = size || inputGroupSize || formControlSize || controlSize
const sizeMetrics = SELECT_SIZE_METRICS[selectSize] const sizeMetrics = SELECT_SIZE_METRICS[selectSize]
const twColor = TW_COLORS as any
let isInvalid = false let isInvalid = false
if (!isEmpty(form)) { if (!isEmpty(form)) {
@ -190,11 +188,11 @@ function SelectBase<
const shadaowBase = '0 0 0 1px ' const shadaowBase = '0 0 0 1px '
if (isInvalid) { if (isInvalid) {
return shadaowBase + twColor.red['500'] return shadaowBase + twColor('red', 500)
} }
if (state.isFocused) { if (state.isFocused) {
return shadaowBase + twColor[themeColor][primaryColorLevel] return shadaowBase + twColor(themeColor, primaryColorLevel)
} }
return 'none' return 'none'
@ -219,8 +217,8 @@ function SelectBase<
cursor: 'pointer', cursor: 'pointer',
}, },
boxShadow: getBoxShadow(state), boxShadow: getBoxShadow(state),
borderRadius: BORDER_RADIUS.md, borderRadius: 'var(--radius-md)',
...(isInvalid ? { borderColor: twColor.red['500'] } : {}), ...(isInvalid ? { borderColor: twColor('red', 500) } : {}),
} }
}, },
input: (css) => { input: (css) => {
@ -257,14 +255,14 @@ function SelectBase<
...theme, ...theme,
colors: { colors: {
...theme.colors, ...theme.colors,
neutral0: mode === 'dark' ? twColor.gray['800'] : (TW_COLORS as any).white, neutral0: mode === 'dark' ? twColor('gray', 800) : twColor('white'),
neutral20: mode === 'dark' ? twColor.gray['600'] : twColor.gray['300'], neutral20: mode === 'dark' ? twColor('gray', 600) : twColor('gray', 300),
neutral30: mode === 'dark' ? twColor.gray['600'] : twColor.gray['300'], neutral30: mode === 'dark' ? twColor('gray', 600) : twColor('gray', 300),
neutral80: mode === 'dark' ? (TW_COLORS as any).white : twColor.gray['700'], neutral80: mode === 'dark' ? twColor('white') : twColor('gray', 700),
neutral10: mode === 'dark' ? twColor.gray['600'] : twColor.gray['300'], neutral10: mode === 'dark' ? twColor('gray', 600) : twColor('gray', 300),
primary25: twColor[themeColor]['50'], primary25: twColor(themeColor, 50),
primary50: twColor[themeColor]['100'], primary50: twColor(themeColor, 100),
primary: twColor[themeColor][primaryColorLevel], primary: twColor(themeColor, primaryColorLevel),
}, },
})} })}
themeColor={`${themeColor}-${primaryColorLevel}`} themeColor={`${themeColor}-${primaryColorLevel}`}

View file

@ -70,7 +70,7 @@ export default function Widget({
<div <div
onClick={onClick} onClick={onClick}
className={classNames( className={classNames(
'bg-white dark:bg-gray-900 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 flex flex-col justify-between', 'bg-white dark:bg-gray-900 rounded-lg shadow-xs border border-gray-200 dark:border-gray-700 p-4 flex flex-col justify-between',
onClick && 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800', onClick && 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800',
className, className,
)} )}
@ -83,7 +83,7 @@ export default function Widget({
</div> </div>
<div <div
className={classNames( className={classNames(
'w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center shadow-sm', 'w-12 h-12 bg-linear-to-br rounded-xl flex items-center justify-center shadow-xs',
colorMap[safeColor].bg, colorMap[safeColor].bg,
'dark:' + colorMap[safeColor].darkBg 'dark:' + colorMap[safeColor].darkBg
)} )}

View file

@ -701,7 +701,7 @@ const PlatformPlaceholder = ({ node }: { node: DesignerNode }) => {
return ( return (
<div <div
className={`flex min-h-40 items-center justify-center rounded-lg border border-dashed border-sky-300 bg-gradient-to-br from-sky-50 to-indigo-50 p-6 text-center dark:border-sky-800 dark:from-slate-900 dark:to-sky-950 ${String(node.props.className || '')}`} className={`flex min-h-40 items-center justify-center rounded-lg border border-dashed border-sky-300 bg-linear-to-br from-sky-50 to-indigo-50 p-6 text-center dark:border-sky-800 dark:from-slate-900 dark:to-sky-950 ${String(node.props.className || '')}`}
style={{ minHeight: String(node.props.height || '320px') }} style={{ minHeight: String(node.props.height || '320px') }}
> >
<div> <div>
@ -740,7 +740,7 @@ const GridColumnHeaders = ({ columns }: { columns: string[] }) => {
const { translate } = useLocalization() const { translate } = useLocalization()
return ( return (
<div className="min-w-0 overflow-auto rounded-md border border-slate-200 bg-slate-100 [grid-column:1/-1] dark:border-slate-700 dark:bg-slate-800"> <div className="min-w-0 overflow-auto rounded-md border border-slate-200 bg-slate-100 col-span-full dark:border-slate-700 dark:bg-slate-800">
{columns.length ? ( {columns.length ? (
<div className="flex min-w-max divide-x divide-slate-200 dark:divide-slate-700"> <div className="flex min-w-max divide-x divide-slate-200 dark:divide-slate-700">
{columns.map((column) => ( {columns.map((column) => (
@ -797,7 +797,7 @@ const GridDataTablePreview = ({
if (!columns.length) { if (!columns.length) {
return ( return (
<div className="rounded-lg border border-dashed border-slate-300 bg-slate-50 p-4 text-center text-xs text-slate-500 [grid-column:1/-1] dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400"> <div className="rounded-lg border border-dashed border-slate-300 bg-slate-50 p-4 text-center text-xs text-slate-500 col-span-full dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400">
{translate('::App.VisualDesignerCanvas.SelectAtLeastOneColumn')} {translate('::App.VisualDesignerCanvas.SelectAtLeastOneColumn')}
</div> </div>
) )
@ -805,7 +805,7 @@ const GridDataTablePreview = ({
return ( return (
<div <div
className={`min-w-0 rounded-lg border border-slate-200 bg-white shadow-sm [grid-column:1/-1] dark:border-slate-700 dark:bg-slate-900 ${overflow ? 'overflow-auto' : 'overflow-visible'}`} className={`min-w-0 rounded-lg border border-slate-200 bg-white shadow-xs col-span-full dark:border-slate-700 dark:bg-slate-900 ${overflow ? 'overflow-auto' : 'overflow-visible'}`}
> >
<table className={`w-full border-collapse text-left ${compact ? 'text-[11px]' : 'text-xs'}`}> <table className={`w-full border-collapse text-left ${compact ? 'text-[11px]' : 'text-xs'}`}>
<thead className="bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-200"> <thead className="bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-200">
@ -1006,7 +1006,7 @@ const FormView = ({
? translate('::App.Platform.RecordCount', { count: rows.length }) ? translate('::App.Platform.RecordCount', { count: rows.length })
: translate('::App.VisualDesignerCanvas.NoSelectEndpoint')} : translate('::App.VisualDesignerCanvas.NoSelectEndpoint')}
</span> </span>
<span className="rounded bg-sky-600 px-1.5 py-0.5 font-semibold text-white"> <span className="rounded-sm bg-sky-600 px-1.5 py-0.5 font-semibold text-white">
{translate( {translate(
mode === 'new' ? '::App.VisualDesignerCanvas.NewRecord' : '::App.Platform.Editing', mode === 'new' ? '::App.VisualDesignerCanvas.NewRecord' : '::App.Platform.Editing',
)} )}
@ -1016,7 +1016,7 @@ const FormView = ({
{translate('::App.Platform.Row')} {translate('::App.Platform.Row')}
<UiKit.Select <UiKit.Select
size="xs" size="xs"
className="min-w-[4.5rem]" className="min-w-18"
maxMenuHeight={200} maxMenuHeight={200}
menuPosition="fixed" menuPosition="fixed"
menuPortalTarget={window.document.body} menuPortalTarget={window.document.body}
@ -1049,7 +1049,7 @@ const FormView = ({
)} )}
{/* The drop zone belongs with the content, above the command toolbar. */} {/* The drop zone belongs with the content, above the command toolbar. */}
{interactive && !node.children.length && ( {interactive && !node.children.length && (
<div className="rounded border border-dashed border-slate-300 px-3 py-4 text-center text-xs text-slate-400 dark:border-slate-700"> <div className="rounded-sm border border-dashed border-slate-300 px-3 py-4 text-center text-xs text-slate-400 dark:border-slate-700">
{translate('::App.VisualDesignerCanvas.DropAndBind')} {translate('::App.VisualDesignerCanvas.DropAndBind')}
</div> </div>
)} )}
@ -1461,7 +1461,7 @@ const HOISTED_LAYOUT_EXACT = new Set([
const SHARED_LAYOUT_PATTERN = /^(absolute|fixed|sticky|w-full|h-full)$|^-?(inset|top|right|bottom|left)-|^z-|^(min|max)-w-/ const SHARED_LAYOUT_PATTERN = /^(absolute|fixed|sticky|w-full|h-full)$|^-?(inset|top|right|bottom|left)-|^z-|^(min|max)-w-/
const NODE_POSITION_PATTERN = /^(absolute|fixed|sticky)$/ const NODE_POSITION_PATTERN = /^(absolute|fixed|sticky)$/
/** `md:`, `dark:hover:` gibi varyant onlerini atar; `[grid-column:1/-1]` bozulmadan kalir. */ /** `md:`, `dark:hover:` gibi varyant onlerini atar; `col-span-full` bozulmadan kalir. */
const stripVariants = (token: string) => token.replace(/^(?:(?:[\w-]+|\[[^\]]+\]):)+/, '') const stripVariants = (token: string) => token.replace(/^(?:(?:[\w-]+|\[[^\]]+\]):)+/, '')
/** /**
@ -1781,7 +1781,7 @@ const NodeView = ({
<div <div
className={`min-h-14 rounded py-2 transition ${ className={`min-h-14 rounded py-2 transition ${
overSlot === slot overSlot === slot
? 'bg-emerald-50 outline outline-2 outline-emerald-500 dark:bg-emerald-950/40' ? 'bg-emerald-50 outline-solid outline-2 outline-emerald-500 dark:bg-emerald-950/40'
: dragging : dragging
? 'outline-dashed outline-1 outline-sky-400/70' ? 'outline-dashed outline-1 outline-sky-400/70'
: '' : ''
@ -1822,7 +1822,7 @@ const NodeView = ({
/> />
))} ))}
{interactive && !tabNodes.length && !option.content && ( {interactive && !tabNodes.length && !option.content && (
<div className="flex min-h-12 items-center justify-center rounded border border-dashed border-slate-300 px-2 text-center text-[10px] text-slate-400 dark:border-slate-700"> <div className="flex min-h-12 items-center justify-center rounded-sm border border-dashed border-slate-300 px-2 text-center text-[10px] text-slate-400 dark:border-slate-700">
{translate('::App.VisualDesignerCanvas.DropComponentInTab')} {translate('::App.VisualDesignerCanvas.DropComponentInTab')}
</div> </div>
)} )}
@ -1838,7 +1838,7 @@ const NodeView = ({
node.type === 'Table' ? ( node.type === 'Table' ? (
<UiKit.Table <UiKit.Table
borderlessRow borderlessRow
className={`${String(node.props.className || '')} [&>tbody>tr>td]:!px-1.5 [&>tbody>tr>td]:!py-1.5`} className={`${String(node.props.className || '')} [&>tbody>tr>td]:px-1.5! [&>tbody>tr>td]:py-1.5!`}
compact={Boolean(node.props.compact)} compact={Boolean(node.props.compact)}
hoverable={node.props.hoverable !== false} hoverable={node.props.hoverable !== false}
overflow={node.props.overflow !== false} overflow={node.props.overflow !== false}
@ -1912,7 +1912,7 @@ const NodeView = ({
/> />
))} ))}
{interactive && !cellNodes.length && ( {interactive && !cellNodes.length && (
<div className="flex min-h-12 items-center justify-center rounded border border-dashed border-slate-300 px-2 text-center text-[10px] text-slate-400 dark:border-slate-700"> <div className="flex min-h-12 items-center justify-center rounded-sm border border-dashed border-slate-300 px-2 text-center text-[10px] text-slate-400 dark:border-slate-700">
{translate('::App.VisualDesignerCanvas.DropComponent')} {translate('::App.VisualDesignerCanvas.DropComponent')}
</div> </div>
)} )}
@ -1972,7 +1972,7 @@ const NodeView = ({
? [ ? [
<div <div
key={`grid_loading_${node.id}`} key={`grid_loading_${node.id}`}
className="rounded-lg border border-slate-200 bg-slate-50 p-4 text-center text-xs text-slate-500 [grid-column:1/-1] dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400" className="rounded-lg border border-slate-200 bg-slate-50 p-4 text-center text-xs text-slate-500 col-span-full dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400"
> >
{translate('::App.VisualDesignerCanvas.LoadingData')} {translate('::App.VisualDesignerCanvas.LoadingData')}
</div>, </div>,
@ -2058,15 +2058,15 @@ const NodeView = ({
isDragSource ? 'opacity-40' : '' isDragSource ? 'opacity-40' : ''
} ${ } ${
dropHint === 'inside' dropHint === 'inside'
? 'z-10 bg-emerald-500/10 outline outline-2 outline-emerald-500 outline-offset-2' ? 'z-10 bg-emerald-500/10 outline-solid outline-2 outline-emerald-500 outline-offset-2'
: // Sürükleme sürerken içine bırakılabilen her konteyner işaretlenir, böylece : // Sürükleme sürerken içine bırakılabilen her konteyner işaretlenir, böylece
// kullanıcı hedefe varmadan önce nereye bırakabileceğini görür. // kullanıcı hedefe varmadan önce nereye bırakabileceğini görür.
dragging && canDropInside dragging && canDropInside
? 'outline-dashed outline-1 outline-sky-400/70 outline-offset-2' ? 'outline-dashed outline-1 outline-sky-400/70 outline-offset-2'
: interactive : interactive
? selected ? selected
? 'z-10 outline outline-2 outline-sky-500 outline-offset-2' ? 'z-10 outline-solid outline-2 outline-sky-500 outline-offset-2'
: 'outline outline-1 outline-transparent hover:outline-sky-300' : 'outline-solid outline-1 outline-transparent hover:outline-sky-300'
: '' : ''
}`} }`}
data-designer-node={node.id} data-designer-node={node.id}
@ -2122,28 +2122,28 @@ const NodeView = ({
{/* Yanına bırakma çizgisi: bileşen tam olarak buraya girer. */} {/* Yanına bırakma çizgisi: bileşen tam olarak buraya girer. */}
{dropHint === 'before' && ( {dropHint === 'before' && (
<div className="pointer-events-none absolute inset-x-0 -top-1 z-30 flex items-center gap-1"> <div className="pointer-events-none absolute inset-x-0 -top-1 z-30 flex items-center gap-1">
<span className="rounded bg-emerald-600 px-1.5 py-[1px] text-[10px] font-semibold text-white shadow"> <span className="rounded-sm bg-emerald-600 px-1.5 py-px text-[10px] font-semibold text-white shadow-sm">
{dragLabel} üstüne {dragLabel} üstüne
</span> </span>
<span className="h-[3px] flex-1 rounded bg-emerald-500" /> <span className="h-[3px] flex-1 rounded-sm bg-emerald-500" />
</div> </div>
)} )}
{dropHint === 'after' && ( {dropHint === 'after' && (
<div className="pointer-events-none absolute inset-x-0 -bottom-1 z-30 flex items-center gap-1"> <div className="pointer-events-none absolute inset-x-0 -bottom-1 z-30 flex items-center gap-1">
<span className="rounded bg-emerald-600 px-1.5 py-[1px] text-[10px] font-semibold text-white shadow"> <span className="rounded-sm bg-emerald-600 px-1.5 py-px text-[10px] font-semibold text-white shadow-sm">
{dragLabel} altına {dragLabel} altına
</span> </span>
<span className="h-[3px] flex-1 rounded bg-emerald-500" /> <span className="h-[3px] flex-1 rounded-sm bg-emerald-500" />
</div> </div>
)} )}
{dropHint === 'inside' && ( {dropHint === 'inside' && (
<span className="pointer-events-none absolute left-1 top-1 z-30 rounded bg-emerald-600 px-1.5 py-[1px] text-[10px] font-semibold text-white shadow"> <span className="pointer-events-none absolute left-1 top-1 z-30 rounded-sm bg-emerald-600 px-1.5 py-px text-[10px] font-semibold text-white shadow-sm">
{node.type} içine {node.type} içine
</span> </span>
)} )}
{/* Sürükleme sürerken bırakılamayan hedef açıkça söylenir. */} {/* Sürükleme sürerken bırakılamayan hedef açıkça söylenir. */}
{dragging && insideDraggedSubtree && !isDragSource && ( {dragging && insideDraggedSubtree && !isDragSource && (
<span className="pointer-events-none absolute right-1 top-1 z-30 rounded bg-slate-500 px-1.5 py-[1px] text-[10px] font-semibold text-white shadow"> <span className="pointer-events-none absolute right-1 top-1 z-30 rounded-sm bg-slate-500 px-1.5 py-px text-[10px] font-semibold text-white shadow-sm">
{translate('::App.VisualDesignerCanvas.CannotMoveHere')} {translate('::App.VisualDesignerCanvas.CannotMoveHere')}
</span> </span>
)} )}
@ -2158,7 +2158,7 @@ const NodeView = ({
{interactive && ( {interactive && (
<span <span
draggable draggable
className={`absolute -right-2 -top-2 z-30 h-4 w-4 cursor-grab items-center justify-center rounded-full bg-sky-600 text-[8px] text-white shadow ring-1 ring-white active:cursor-grabbing dark:ring-gray-900 ${selected ? 'flex' : 'hidden'}`} className={`absolute -right-2 -top-2 z-30 h-4 w-4 cursor-grab items-center justify-center rounded-full bg-sky-600 text-[8px] text-white shadow-sm ring-1 ring-white active:cursor-grabbing dark:ring-gray-900 ${selected ? 'flex' : 'hidden'}`}
title={translate('::App.VisualDesignerCanvas.DragToMove', { title={translate('::App.VisualDesignerCanvas.DragToMove', {
name: node.ref || node.type, name: node.ref || node.type,
})} })}
@ -2169,7 +2169,7 @@ const NodeView = ({
</span> </span>
)} )}
{interactive && refHidden && ( {interactive && refHidden && (
<span className="absolute left-1 top-1 z-10 rounded bg-slate-700 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wider text-white"> <span className="absolute left-1 top-1 z-10 rounded-sm bg-slate-700 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wider text-white">
Gizli Gizli
</span> </span>
)} )}
@ -2204,7 +2204,7 @@ const NodeView = ({
// Form renders its own placeholder below the toolbar. // Form renders its own placeholder below the toolbar.
!isFormNode(node.type) && ( !isFormNode(node.type) && (
<div <div
className="m-2 rounded border border-dashed border-slate-300 px-3 py-4 text-center text-xs text-slate-400" className="m-2 rounded-sm border border-dashed border-slate-300 px-3 py-4 text-center text-xs text-slate-400"
{...containerDropZoneProps} {...containerDropZoneProps}
> >
{translate('::App.VisualDesignerCanvas.DropComponentHere')} {translate('::App.VisualDesignerCanvas.DropComponentHere')}
@ -2399,7 +2399,7 @@ const VisualCanvas = ({
].map(([name, icon]) => ( ].map(([name, icon]) => (
<button <button
key={name} key={name}
className="rounded-lg border border-slate-200 bg-white p-3 text-xs font-semibold text-slate-600 shadow-sm transition hover:border-sky-400 hover:text-sky-700 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300" className="rounded-lg border border-slate-200 bg-white p-3 text-xs font-semibold text-slate-600 shadow-xs transition hover:border-sky-400 hover:text-sky-700 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300"
type="button" type="button"
onClick={(event) => { onClick={(event) => {
event.stopPropagation() event.stopPropagation()

View file

@ -979,7 +979,7 @@ const renderNodeToCode = (
return `${indent('<tr>', level + 1)}\n${cells}\n${indent('</tr>', level + 1)}` return `${indent('<tr>', level + 1)}\n${cells}\n${indent('</tr>', level + 1)}`
}).join('\n') }).join('\n')
const className = JSON.stringify(String(node.props.className || '')) const className = JSON.stringify(String(node.props.className || ''))
return `${indent(`<UiKit.Table className={${className} + " [&>tbody>tr>td]:!px-1.5 [&>tbody>tr>td]:!py-1.5"} borderlessRow compact={${Boolean(node.props.compact)}} hoverable={${node.props.hoverable !== false}} overflow={${node.props.overflow !== false}} style={{ minWidth: "100%", tableLayout: "fixed", width: "100%" }}>`, level)} return `${indent(`<UiKit.Table className={${className} + " [&>tbody>tr>td]:px-1.5! [&>tbody>tr>td]:py-1.5!"} borderlessRow compact={${Boolean(node.props.compact)}} hoverable={${node.props.hoverable !== false}} overflow={${node.props.overflow !== false}} style={{ minWidth: "100%", tableLayout: "fixed", width: "100%" }}>`, level)}
${indent('<tbody>', level + 1)} ${indent('<tbody>', level + 1)}
${rows} ${rows}
${indent('</tbody>', level + 1)} ${indent('</tbody>', level + 1)}
@ -1058,7 +1058,7 @@ ${indent(`if (!Array.isArray(${itemsVariable})) return <div className="rounded-l
${indent(`const ${columnsVariable} = ${columnsExpression}`, level + 2)} ${indent(`const ${columnsVariable} = ${columnsExpression}`, level + 2)}
${captionEntries.length ? `${indent(`const ${captionsVariable} = ${captionsLiteral}`, level + 2)}\n` : ''}${lookupEntries.length ? `${indent(`const ${lookupsVariable} = ${lookupsLiteral}`, level + 2)}\n` : ''}${indent(`if (!${columnsVariable}.length) return <div className="rounded-lg border border-dashed border-slate-300 bg-slate-50 p-4 text-center text-xs text-slate-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400">Preview için en az bir sütun seçin.</div>`, level + 2)} ${captionEntries.length ? `${indent(`const ${captionsVariable} = ${captionsLiteral}`, level + 2)}\n` : ''}${lookupEntries.length ? `${indent(`const ${lookupsVariable} = ${lookupsLiteral}`, level + 2)}\n` : ''}${indent(`if (!${columnsVariable}.length) return <div className="rounded-lg border border-dashed border-slate-300 bg-slate-50 p-4 text-center text-xs text-slate-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400">Preview için en az bir sütun seçin.</div>`, level + 2)}
${indent('return (', level + 2)} ${indent('return (', level + 2)}
${indent(`<div className="min-w-0 ${overflowClass} rounded-lg border border-slate-200 bg-white shadow-sm dark:border-slate-700 dark:bg-slate-900" style={{ gridColumn: "1 / -1" }}>`, level + 3)} ${indent(`<div className="min-w-0 ${overflowClass} rounded-lg border border-slate-200 bg-white shadow-xs dark:border-slate-700 dark:bg-slate-900" style={{ gridColumn: "1 / -1" }}>`, level + 3)}
${indent(`<table className="w-full border-collapse text-left ${tableTextClass}">`, level + 4)} ${indent(`<table className="w-full border-collapse text-left ${tableTextClass}">`, level + 4)}
${indent('<thead className="bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-200"><tr>', level + 5)} ${indent('<thead className="bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-200"><tr>', level + 5)}
${indent(`{${columnsVariable}.map((column) => <th key={column} className="whitespace-nowrap border-b border-slate-200 dark:border-slate-700 ${cellSpacingClass}">{${captionEntries.length ? `${captionsVariable}[column] ?? ` : ''}(column === "value" ? "Value" : column)}</th>)}`, level + 6)} ${indent(`{${columnsVariable}.map((column) => <th key={column} className="whitespace-nowrap border-b border-slate-200 dark:border-slate-700 ${cellSpacingClass}">{${captionEntries.length ? `${captionsVariable}[column] ?? ` : ''}(column === "value" ? "Value" : column)}</th>)}`, level + 6)}
@ -1091,7 +1091,7 @@ ${indent('})()}', level + 1)}`
.map((child) => nodeToCode(child, level + 4, repeatedItemVariable, formScope)) .map((child) => nodeToCode(child, level + 4, repeatedItemVariable, formScope))
.join('\n') .join('\n')
: indent( : indent(
`<pre className="min-w-0 overflow-auto rounded-lg border border-slate-200 bg-white p-3 text-xs text-slate-800 shadow-sm dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100">{typeof ${repeatedItemVariable} === "string" ? ${repeatedItemVariable} : JSON.stringify(${repeatedItemVariable}, null, 2)}</pre>`, `<pre className="min-w-0 overflow-auto rounded-lg border border-slate-200 bg-white p-3 text-xs text-slate-800 shadow-xs dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100">{typeof ${repeatedItemVariable} === "string" ? ${repeatedItemVariable} : JSON.stringify(${repeatedItemVariable}, null, 2)}</pre>`,
level + 4, level + 4,
) )
// The collection is read once into a local: it is tested for three cases // The collection is read once into a local: it is tested for three cases

View file

@ -1,12 +1,12 @@
/** Liste/kart yonetim ekranlarindaki aksiyon ikonlari notr durur, rengi yalnizca hover'da gosterir. */ /** Liste/kart yonetim ekranlarindaki aksiyon ikonlari notr durur, rengi yalnizca hover'da gosterir. */
export const ACTION_BUTTON_CLASS = export const ACTION_BUTTON_CLASS =
'!h-8 !w-8 !rounded !p-0 text-slate-500 transition-colors dark:text-gray-400' 'h-8! w-8! rounded-sm! p-0! text-slate-500 transition-colors dark:text-gray-400'
export const ACTION_BUTTON_HOVER = { export const ACTION_BUTTON_HOVER = {
blue: 'hover:!bg-blue-50 hover:text-blue-600 dark:hover:!bg-gray-800 dark:hover:text-blue-400', blue: 'hover:bg-blue-50! hover:text-blue-600 dark:hover:bg-gray-800! dark:hover:text-blue-400',
green: green:
'hover:!bg-green-50 hover:text-green-600 dark:hover:!bg-gray-800 dark:hover:text-green-400', 'hover:bg-green-50! hover:text-green-600 dark:hover:bg-gray-800! dark:hover:text-green-400',
red: 'hover:!bg-red-50 hover:text-red-600 dark:hover:!bg-gray-800 dark:hover:text-red-400', red: 'hover:bg-red-50! hover:text-red-600 dark:hover:bg-gray-800! dark:hover:text-red-400',
slate: slate:
'hover:!bg-slate-100 hover:text-slate-700 dark:hover:!bg-gray-800 dark:hover:text-gray-200', 'hover:bg-slate-100! hover:text-slate-700 dark:hover:bg-gray-800! dark:hover:text-gray-200',
} as const } as const

Binary file not shown.

View file

@ -139,5 +139,4 @@ export abstract class UiEvalService {
} }
} }
const _global = (window || global) as any ;(globalThis as any).UiEvalService = UiEvalService
_global.UiEvalService = UiEvalService

View file

@ -107,7 +107,7 @@ function useAuth() {
access_token: token, access_token: token,
refresh_token: refreshToken, refresh_token: refreshToken,
expires_in: expiresIn, expires_in: expiresIn,
} = resp?.data as any } = resp.data as any
handleToken({ token, refreshToken, expiresIn }) handleToken({ token, refreshToken, expiresIn })
// if (resp.data.user) { // if (resp.data.user) {
// setUser( // setUser(

View file

@ -1,13 +1,5 @@
// src/utils/tailwind.ts // src/utils/tailwind.ts
import colors from 'tailwindcss/colors'
// Tailwind eski renk isimlerinden kaynaklı uyarıları engelle
delete (colors as any).lightBlue
delete (colors as any).warmGray
delete (colors as any).trueGray
delete (colors as any).coolGray
delete (colors as any).blueGray
// Tailwind breakpoints (px) // Tailwind breakpoints (px)
export const SCREENS = { export const SCREENS = {
xs: 576, xs: 576,
@ -18,28 +10,9 @@ export const SCREENS = {
'2xl': 1536, '2xl': 1536,
} as const } as const
// Border radius (Tailwind ile uyumlu) /**
export const BORDER_RADIUS = { * Temanin renk degiskeni (`@theme`, src/assets/styles/tailwind/index.css). Deger koda kopyalanmaz;
none: '0px', * ozel gri paleti ve `sozsoft-*` renkleri dahil, CSS ile JS ayni rengi gosterir.
xs: '0.0625rem', */
sm: '0.125rem', export const themeColor = (name: string, shade?: string | number) =>
DEFAULT: '0.25rem', `var(--color-${shade === undefined ? name : `${name}-${shade}`})`
md: '0.375rem',
lg: '0.5rem',
xl: '0.75rem',
'2xl': '1rem',
'3xl': '1.5rem',
full: '9999px',
} as const
// Tailwind renk paleti + senin custom 'sozsoft' renklerin
export const TW_COLORS = {
...colors,
sozsoft: {
main: '#FF99C8',
secondary: '#FCF6BD',
active: '#D0F4DE',
x: '#A9DEF9',
y: '#E4C1F9',
},
} as const

Some files were not shown because too many files have changed in this diff Show more