|
@@ -7,7 +7,7 @@ type Obj = {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
type Store = {
|
|
type Store = {
|
|
|
- rawVariables: Obj[];
|
|
|
|
|
|
|
+ variables: Obj[];
|
|
|
variablesMap: Obj;
|
|
variablesMap: Obj;
|
|
|
rawStyles: Obj;
|
|
rawStyles: Obj;
|
|
|
[k: string]: any;
|
|
[k: string]: any;
|
|
@@ -15,7 +15,7 @@ type Store = {
|
|
|
|
|
|
|
|
const components = configs.nav.map(({ packages }) => packages.map(({ name }) => name)).flat(1);
|
|
const components = configs.nav.map(({ packages }) => packages.map(({ name }) => name)).flat(1);
|
|
|
|
|
|
|
|
-const getGithubRawFile = async function (url: string) {
|
|
|
|
|
|
|
+const getRawFileText = async function (url: string) {
|
|
|
const response = await fetch(url);
|
|
const response = await fetch(url);
|
|
|
const res = await response.text();
|
|
const res = await response.text();
|
|
|
return res;
|
|
return res;
|
|
@@ -47,16 +47,8 @@ const awaitIframe = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const cachedStyles: Obj = {};
|
|
|
|
|
-const store: Store = reactive({
|
|
|
|
|
- init: false,
|
|
|
|
|
- rawVariables: [],
|
|
|
|
|
- variablesMap: {},
|
|
|
|
|
- rawStyles: {}
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// 提取变量,区分base和组件
|
|
|
|
|
-const extractVariable = (matched: string[], variables: string, name: string, lowerCaseName: string) =>
|
|
|
|
|
|
|
+// 提取变量
|
|
|
|
|
+const extractVariables = (matched: string[], name: string, lowerCaseName: string) =>
|
|
|
matched.reduce((res, str) => {
|
|
matched.reduce((res, str) => {
|
|
|
const extract = str.replace(/\s+!default/, '').match(/(.*):(?:\s+)?([\s\S]*)(?:\s+)?;/);
|
|
const extract = str.replace(/\s+!default/, '').match(/(.*):(?:\s+)?([\s\S]*)(?:\s+)?;/);
|
|
|
|
|
|
|
@@ -76,19 +68,33 @@ const extractVariable = (matched: string[], variables: string, name: string, low
|
|
|
}
|
|
}
|
|
|
return res;
|
|
return res;
|
|
|
}, [] as Obj[]);
|
|
}, [] as Obj[]);
|
|
|
-const getSassVariables = async (url: string) => {
|
|
|
|
|
- if (Object.keys(store.rawVariables).length) {
|
|
|
|
|
- return store;
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 提取样式代码,只保留有使用变量的行
|
|
|
|
|
+const extractStyle = (style: string) => {
|
|
|
|
|
+ if (!store.variables.length) {
|
|
|
|
|
+ return '';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const variables = await getGithubRawFile(url);
|
|
|
|
|
|
|
+ const extract = style.split('\n').filter((str) => {
|
|
|
|
|
+ const matched = str.match(/\$[\w-]+\b/g);
|
|
|
|
|
+
|
|
|
|
|
+ if (matched) {
|
|
|
|
|
+ return matched.some((k) => store.variablesMap[k]);
|
|
|
|
|
+ }
|
|
|
|
|
+ return /(\{|\})/.test(str);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return extract.join('');
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const parseSassVariables = (text: string, components: string[]) => {
|
|
|
const matchedComponentVariables = components
|
|
const matchedComponentVariables = components
|
|
|
.map((name) => {
|
|
.map((name) => {
|
|
|
const lowerCaseName = name.toLowerCase();
|
|
const lowerCaseName = name.toLowerCase();
|
|
|
const reg = new RegExp(`(?<!\\/\\/(\\s+)?)\\$(${name}|${lowerCaseName})\\b[\\w-]+:[^:;]+;`, 'g');
|
|
const reg = new RegExp(`(?<!\\/\\/(\\s+)?)\\$(${name}|${lowerCaseName})\\b[\\w-]+:[^:;]+;`, 'g');
|
|
|
- const matched = variables.match(reg);
|
|
|
|
|
|
|
+ const matched = text.match(reg);
|
|
|
if (matched) {
|
|
if (matched) {
|
|
|
- return extractVariable(matched, variables, name, lowerCaseName);
|
|
|
|
|
|
|
+ return extractVariables(matched, name, lowerCaseName);
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
.filter(Boolean)
|
|
.filter(Boolean)
|
|
@@ -101,42 +107,61 @@ const getSassVariables = async (url: string) => {
|
|
|
'g'
|
|
'g'
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- const rawVariables = matchedComponentVariables as Obj[];
|
|
|
|
|
|
|
+ const variables = matchedComponentVariables as Obj[];
|
|
|
|
|
|
|
|
- const matchedBaseVariables = variables.match(baseVariablesReg);
|
|
|
|
|
|
|
+ const matchedBaseVariables = text.match(baseVariablesReg);
|
|
|
|
|
|
|
|
|
|
+ // 组件变量以外的都作为基础变量
|
|
|
if (matchedBaseVariables) {
|
|
if (matchedBaseVariables) {
|
|
|
- rawVariables.unshift(...extractVariable(matchedBaseVariables, variables, 'Base', 'base'));
|
|
|
|
|
|
|
+ variables.unshift(...extractVariables(matchedBaseVariables, 'Base', 'base'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return variables;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const cachedStyles: Obj = {};
|
|
|
|
|
+const store: Store = reactive({
|
|
|
|
|
+ init: false,
|
|
|
|
|
+ variables: [],
|
|
|
|
|
+ variablesMap: {},
|
|
|
|
|
+ rawStyles: {}
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const getSassVariables = async () => {
|
|
|
|
|
+ const rawVariablesText = await getRawFileText(
|
|
|
|
|
+ '/devRaw/jd-platform-opensource/nutui/raw/next/src/packages/styles/variables.scss'
|
|
|
|
|
+ );
|
|
|
|
|
+ const rawVariables = parseSassVariables(rawVariablesText, components);
|
|
|
|
|
+
|
|
|
|
|
+ // 固定自定义主题的访问链接: https://nutui.jd.com/theme/?theme=自定义变量的文件地址#/
|
|
|
|
|
+ // e.g. https://nutui.jd.com/theme/?theme=xxx.com%2variables.scss#/
|
|
|
|
|
+ // vite issue https://github.com/vitejs/vite/issues/6894
|
|
|
|
|
+ const params = new URLSearchParams(window.location.search);
|
|
|
|
|
+ const customUrl = params.get('theme');
|
|
|
|
|
+ if (customUrl) {
|
|
|
|
|
+ const customVariablesText = await getRawFileText(customUrl);
|
|
|
|
|
+ const customVariables = parseSassVariables(customVariablesText, components);
|
|
|
|
|
+
|
|
|
|
|
+ // merge
|
|
|
|
|
+ rawVariables.forEach((item) => {
|
|
|
|
|
+ const custom = customVariables.find(({ key }) => key === item.key);
|
|
|
|
|
+ if (custom) {
|
|
|
|
|
+ item.value = custom.value;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const variablesMap = rawVariables.reduce((map, item) => {
|
|
const variablesMap = rawVariables.reduce((map, item) => {
|
|
|
map[item.key] = 1;
|
|
map[item.key] = 1;
|
|
|
return map;
|
|
return map;
|
|
|
}, {});
|
|
}, {});
|
|
|
- store.rawVariables = rawVariables;
|
|
|
|
|
|
|
+ store.variables = rawVariables;
|
|
|
store.variablesMap = variablesMap;
|
|
store.variablesMap = variablesMap;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 提取样式代码,只保留有使用变量的行
|
|
|
|
|
-const extractStyle = (style: string) => {
|
|
|
|
|
- if (!store.rawVariables.length) {
|
|
|
|
|
- return '';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const extract = style.split('\n').filter((str) => {
|
|
|
|
|
- const matched = str.match(/\$[\w-]+\b/g);
|
|
|
|
|
-
|
|
|
|
|
- if (matched) {
|
|
|
|
|
- return matched.some((k) => store.variablesMap[k]);
|
|
|
|
|
- }
|
|
|
|
|
- return /(\{|\})/.test(str);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- return extract.join('');
|
|
|
|
|
-};
|
|
|
|
|
-export const getSassStyle = async (name: string): Promise<void> => {
|
|
|
|
|
|
|
+export const getRawSassStyle = async (name: string): Promise<void> => {
|
|
|
if (!store.rawStyles[name]) {
|
|
if (!store.rawStyles[name]) {
|
|
|
- const style = await getGithubRawFile(
|
|
|
|
|
|
|
+ const style = await getRawFileText(
|
|
|
`/devRaw/jd-platform-opensource/nutui/raw/next/src/packages/__VUE/${name}/index.scss`
|
|
`/devRaw/jd-platform-opensource/nutui/raw/next/src/packages/__VUE/${name}/index.scss`
|
|
|
);
|
|
);
|
|
|
store.rawStyles[name] = style;
|
|
store.rawStyles[name] = style;
|
|
@@ -147,7 +172,7 @@ export const useThemeEditor = function (): Obj {
|
|
|
const route = useRoute();
|
|
const route = useRoute();
|
|
|
|
|
|
|
|
const cssText = computed(() => {
|
|
const cssText = computed(() => {
|
|
|
- const variablesText = store.rawVariables.map(({ key, value }) => `${key}:${value}`).join(';');
|
|
|
|
|
|
|
+ const variablesText = store.variables.map(({ key, value }) => `${key}:${value}`).join(';');
|
|
|
|
|
|
|
|
const styleText = Object.keys(store.rawStyles)
|
|
const styleText = Object.keys(store.rawStyles)
|
|
|
.map((name) => {
|
|
.map((name) => {
|
|
@@ -162,15 +187,12 @@ export const useThemeEditor = function (): Obj {
|
|
|
const formItems = computed(() => {
|
|
const formItems = computed(() => {
|
|
|
const name = route.path.substring(1);
|
|
const name = route.path.substring(1);
|
|
|
|
|
|
|
|
- return store.rawVariables.filter(({ lowerCaseName }) => lowerCaseName === name);
|
|
|
|
|
|
|
+ return store.variables.filter(({ lowerCaseName }) => lowerCaseName === name);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
|
if (!store.init) {
|
|
if (!store.init) {
|
|
|
- await Promise.all([
|
|
|
|
|
- getSassVariables('/devRaw/jd-platform-opensource/nutui/raw/next/src/packages/styles/variables.scss'),
|
|
|
|
|
- loadScript('https://cdnout.com/sass.js/sass.sync.min.js')
|
|
|
|
|
- ]);
|
|
|
|
|
|
|
+ await Promise.all([getSassVariables(), loadScript('https://cdnout.com/sass.js/sass.sync.min.js')]);
|
|
|
store.init = true;
|
|
store.init = true;
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -180,7 +202,7 @@ export const useThemeEditor = function (): Obj {
|
|
|
(path) => {
|
|
(path) => {
|
|
|
const name = path.substring(1);
|
|
const name = path.substring(1);
|
|
|
if (name !== 'base') {
|
|
if (name !== 'base') {
|
|
|
- getSassStyle(name);
|
|
|
|
|
|
|
+ getRawSassStyle(name);
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
@@ -220,12 +242,12 @@ export const useThemeEditor = function (): Obj {
|
|
|
return {
|
|
return {
|
|
|
formItems,
|
|
formItems,
|
|
|
downloadScssVariables() {
|
|
downloadScssVariables() {
|
|
|
- if (!store.rawVariables.length) {
|
|
|
|
|
|
|
+ if (!store.variables.length) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let temp = '';
|
|
let temp = '';
|
|
|
- const variablesText = store.rawVariables
|
|
|
|
|
|
|
+ const variablesText = store.variables
|
|
|
.map(({ name, key, value }) => {
|
|
.map(({ name, key, value }) => {
|
|
|
let comment = '';
|
|
let comment = '';
|
|
|
if (temp !== name) {
|
|
if (temp !== name) {
|