Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/theme-saas/src/old-theme-index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
id: 'tiny-old-theme',
name: 'OldTheme',
cnName: '旧的主题',
css: ``
}
Comment on lines +1 to +6
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure that tinyOldTheme contains theme data or CSS

The tinyOldTheme object currently has an empty css string and lacks any data properties. Applying this theme may not result in any style changes since there are no styles or variables defined.

Consider adding relevant data or css content to tinyOldTheme to ensure that it applies the expected styles when used.

140 changes: 24 additions & 116 deletions packages/theme-saas/src/theme-tool.js
Original file line number Diff line number Diff line change
@@ -1,132 +1,40 @@
/**
* Copyright (c) 2022 - present TinyVue Authors.
* Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import tinyOldTheme from './old-theme-index.js'

import definedComponents from './theme.config'
export { tinyOldTheme }

/**
* TinyVue主题切换类 负责CSS变量主题的装卸,主题元数据转换成主题数据
* 使用示例:new TinyThemeTool(theme,'styleSheetId')
* @param {Object} theme 主题配置数据,结构如下:
* {
* id: 'tiny-infinity-theme',
* name: 'Infinity',
* cnName: '无限',
* data: {'ti-base-color': 'white'}
* }
* @param {String} styleSheetId style标签的id
* 动态切换文档或影子根节点的样式类
*/

export default class TinyThemeTool {
// 当前主题
currentTheme

// 当前style标签元素
contentElement

// 当前style标签的id
styleSheetId

// 默认主题

defaultTheme = {
id: 'tiny-default-theme',
name: 'Default',
cnName: '默认',
data: {}
}

constructor(theme, styleSheetId = 'tinyThemeVariables') {
let currentTheme = theme
if (!theme) {
currentTheme = this.defaultTheme
constructor(theme) {
this.loaded = {} // 缓存已加载的样式
if (theme) {
this.changeTheme(theme)
}
this.styleSheetId = styleSheetId
this.changeTheme(currentTheme)
}

changeTheme(theme) {
let currentTheme = theme
if (typeof window === 'undefined' || typeof document === 'undefined') {
throw new TypeError('当前主题工具只支持浏览器环境')
}
if (!theme) {
currentTheme = this.defaultTheme
}
this.currentTheme = currentTheme
if (!this.contentElement) {
const styleElement = document.getElementById(this.styleSheetId)
if (styleElement) {
this.contentElement = styleElement
} else {
this.contentElement = document.createElement('style')
this.contentElement.id = this.styleSheetId
document.head.appendChild(this.contentElement)
}
changeTheme(theme, target = document) {
let loadedSheet = this.loaded[target]
if (!loadedSheet) {
loadedSheet = new CSSStyleSheet()
target.adoptedStyleSheets = [...target.adoptedStyleSheets, loadedSheet]
this.loaded[target] = loadedSheet
}
this.contentElement.textContent = this.formatCSSVariables(currentTheme.data)

this.contentElement.setAttribute('tiny-theme', this.currentTheme.id)
}
if (theme && (theme.data || theme.css)) {
let cssContent = ''
if (theme.data && typeof theme.data === 'object') {
cssContent = Object.keys(theme.data)
.map((key) => `--${key}: ${theme.data[key]}; `)
.join('')

// 通过 `组件css变量`,来推导出组件名: 从 ti-checkbox-button-bg-color, 推导出 checkbox-button
findClassName(name) {
const compNameList = name.split('-')
if (compNameList.length < 2) {
return false
}
const compLength = definedComponents.length
let compName = ''
for (let i = 0; i < compLength; i++) {
// 先试试是不是双段式的组件名: 比如dialog-box 这种
if (definedComponents[i] === `${compNameList[1]}-${compNameList[2]}`) {
compName = `tiny-${definedComponents[i]}`
break
cssContent = `:root{${cssContent}}`
}
}
// 不是双段的组件,则取第一位为组件名
if (!compName) {
compName = `tiny-${compNameList[1]}`
}

// 提高权重,促使主题变换成功
compName = `${compName}[class*=tiny]`
return compName
}

formatCSSVariables(themeData) {
const componentsMap = {}
let rootCssVar = 'html:root {'
let componentsCssVar = ''

Object.keys(themeData).forEach((item) => {
const isBaseCssVar = item.startsWith('ti-base') || item.startsWith('ti-common')
if (isBaseCssVar) {
rootCssVar += `--${item}:${themeData[item]};`
} else {
const classkey = this.findClassName(item)
if (classkey) {
if (componentsMap[classkey]) {
componentsMap[classkey].push(`--${item}:${themeData[item]};`)
} else {
componentsMap[classkey] = [`--${item}:${themeData[item]};`]
}
}
if (theme.css && typeof theme.css === 'string') {
cssContent += theme.css
}
})

Object.keys(componentsMap).forEach((item) => {
componentsCssVar += `.${item}{${componentsMap[item].join('')}}`
})

return `${rootCssVar}}${componentsCssVar}`
loadedSheet.replaceSync(cssContent)
}
Comment on lines +16 to +38
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure cross-browser compatibility for adoptedStyleSheets and CSSStyleSheet

The use of CSSStyleSheet and adoptedStyleSheets is not supported in all browsers, such as older versions of Safari and Firefox. This could cause the theme switching functionality to fail or lead to runtime errors in unsupported browsers.

Consider adding a fallback mechanism for browsers that do not support these features. You can check for support and use a <style> element as a fallback. Apply this diff to implement the fallback:

 changeTheme(theme, target = document) {
   let loadedSheet = this.loaded[target]
   if (!loadedSheet) {
-    loadedSheet = new CSSStyleSheet()
-    target.adoptedStyleSheets = [...target.adoptedStyleSheets, loadedSheet]
+    if ('adoptedStyleSheets' in Document.prototype && 'replaceSync' in CSSStyleSheet.prototype) {
+      loadedSheet = new CSSStyleSheet()
+      target.adoptedStyleSheets = [...target.adoptedStyleSheets, loadedSheet]
+    } else {
+      loadedSheet = document.createElement('style')
+      target.head.appendChild(loadedSheet)
+    }
     this.loaded[target] = loadedSheet
   }

   if (theme && (theme.data || theme.css)) {
     let cssContent = ''
     if (theme.data && typeof theme.data === 'object') {
       cssContent = Object.keys(theme.data)
         .map((key) => `--${key}: ${theme.data[key]}; `)
         .join('')
       cssContent = `:root{${cssContent}}`
     }
     if (theme.css && typeof theme.css === 'string') {
       cssContent += theme.css
     }
-    loadedSheet.replaceSync(cssContent)
+    if (loadedSheet.replaceSync) {
+      loadedSheet.replaceSync(cssContent)
+    } else {
+      loadedSheet.textContent = cssContent
+    }
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
changeTheme(theme, target = document) {
let loadedSheet = this.loaded[target]
if (!loadedSheet) {
loadedSheet = new CSSStyleSheet()
target.adoptedStyleSheets = [...target.adoptedStyleSheets, loadedSheet]
this.loaded[target] = loadedSheet
}
this.contentElement.textContent = this.formatCSSVariables(currentTheme.data)
this.contentElement.setAttribute('tiny-theme', this.currentTheme.id)
}
if (theme && (theme.data || theme.css)) {
let cssContent = ''
if (theme.data && typeof theme.data === 'object') {
cssContent = Object.keys(theme.data)
.map((key) => `--${key}: ${theme.data[key]}; `)
.join('')
// 通过 `组件css变量`,来推导出组件名: 从 ti-checkbox-button-bg-color, 推导出 checkbox-button
findClassName(name) {
const compNameList = name.split('-')
if (compNameList.length < 2) {
return false
}
const compLength = definedComponents.length
let compName = ''
for (let i = 0; i < compLength; i++) {
// 先试试是不是双段式的组件名: 比如dialog-box 这种
if (definedComponents[i] === `${compNameList[1]}-${compNameList[2]}`) {
compName = `tiny-${definedComponents[i]}`
break
cssContent = `:root{${cssContent}}`
}
}
// 不是双段的组件,则取第一位为组件名
if (!compName) {
compName = `tiny-${compNameList[1]}`
}
// 提高权重,促使主题变换成功
compName = `${compName}[class*=tiny]`
return compName
}
formatCSSVariables(themeData) {
const componentsMap = {}
let rootCssVar = 'html:root {'
let componentsCssVar = ''
Object.keys(themeData).forEach((item) => {
const isBaseCssVar = item.startsWith('ti-base') || item.startsWith('ti-common')
if (isBaseCssVar) {
rootCssVar += `--${item}:${themeData[item]};`
} else {
const classkey = this.findClassName(item)
if (classkey) {
if (componentsMap[classkey]) {
componentsMap[classkey].push(`--${item}:${themeData[item]};`)
} else {
componentsMap[classkey] = [`--${item}:${themeData[item]};`]
}
}
if (theme.css && typeof theme.css === 'string') {
cssContent += theme.css
}
})
Object.keys(componentsMap).forEach((item) => {
componentsCssVar += `.${item}{${componentsMap[item].join('')}}`
})
return `${rootCssVar}}${componentsCssVar}`
loadedSheet.replaceSync(cssContent)
}
changeTheme(theme, target = document) {
let loadedSheet = this.loaded[target]
if (!loadedSheet) {
if ('adoptedStyleSheets' in Document.prototype && 'replaceSync' in CSSStyleSheet.prototype) {
loadedSheet = new CSSStyleSheet()
target.adoptedStyleSheets = [...target.adoptedStyleSheets, loadedSheet]
} else {
loadedSheet = document.createElement('style')
target.head.appendChild(loadedSheet)
}
this.loaded[target] = loadedSheet
}
if (theme && (theme.data || theme.css)) {
let cssContent = ''
if (theme.data && typeof theme.data === 'object') {
cssContent = Object.keys(theme.data)
.map((key) => `--${key}: ${theme.data[key]}; `)
.join('')
cssContent = `:root{${cssContent}}`
}
if (theme.css && typeof theme.css === 'string') {
cssContent += theme.css
}
if (loadedSheet.replaceSync) {
loadedSheet.replaceSync(cssContent)
} else {
loadedSheet.textContent = cssContent
}
}

}
}
1 change: 0 additions & 1 deletion packages/theme-saas/src/theme/aurora-theme/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions packages/theme-saas/src/theme/deep-theme/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions packages/theme-saas/src/theme/galaxy-theme/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions packages/theme-saas/src/theme/impression-theme/index.js

This file was deleted.

61 changes: 0 additions & 61 deletions packages/theme-saas/src/theme/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions packages/theme-saas/src/theme/infinity-theme/index.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/theme-saas/src/theme/smb-theme/index.js

This file was deleted.

10 changes: 0 additions & 10 deletions packages/theme-saas/src/theme/utils.js

This file was deleted.

Loading