Feature(custom): allow user to edit theme file

This commit is contained in:
Kuingsmile
2026-01-26 21:51:07 +08:00
parent 0145ce2aa7
commit e16a3dd90a
12 changed files with 188 additions and 72 deletions

View File

@@ -84,6 +84,7 @@
}, },
"devDependencies": { "devDependencies": {
"@codemirror/commands": "^6.10.1", "@codemirror/commands": "^6.10.1",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-javascript": "^6.2.4", "@codemirror/lang-javascript": "^6.2.4",
"@codemirror/lang-json": "^6.0.2", "@codemirror/lang-json": "^6.0.2",
"@codemirror/search": "^6.6.0", "@codemirror/search": "^6.6.0",

View File

@@ -1,6 +1,6 @@
import path from 'node:path' import path from 'node:path'
import { dataDir, scriptsDir } from '@core/datastore/dirs' import { appGUILogPath, appLogPath, dataDir, manageLogPath, scriptsDir } from '@core/datastore/dirs'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import { IpcMainEvent, shell } from 'electron' import { IpcMainEvent, shell } from 'electron'
import fs from 'fs-extra' import fs from 'fs-extra'
@@ -38,7 +38,20 @@ export default [
{ {
action: IRPCActionType.PICLIST_OPEN_FILE, action: IRPCActionType.PICLIST_OPEN_FILE,
handler: async (_: IIPCEvent, args: [fileName: string]) => { handler: async (_: IIPCEvent, args: [fileName: string]) => {
const abFilePath = path.join(STORE_PATH, args[0]) let abFilePath = path.join(STORE_PATH, args[0])
switch (args[0]) {
case 'piclist.log':
abFilePath = appLogPath()
break
case 'piclist-gui-local.log':
abFilePath = appGUILogPath()
break
case 'manage.log':
abFilePath = manageLogPath()
break
default:
abFilePath = path.join(STORE_PATH, args[0])
}
if (!fs.existsSync(abFilePath)) { if (!fs.existsSync(abFilePath)) {
fs.writeFileSync(abFilePath, '') fs.writeFileSync(abFilePath, '')
} }

View File

@@ -1,6 +1,9 @@
import { isPortable } from '@core/datastore/dirs' import path from 'node:path'
import { isPortable, themesDir } from '@core/datastore/dirs'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import { app, nativeTheme, shell } from 'electron' import { app, nativeTheme, shell } from 'electron'
import fs from 'fs-extra'
import { applyTheme, fetchThemes, importThemes, readTheme, resolveThemes } from '~/apis/app/theme' import { applyTheme, fetchThemes, importThemes, readTheme, resolveThemes } from '~/apis/app/theme'
import { i18nManager } from '~/i18n' import { i18nManager } from '~/i18n'
@@ -54,6 +57,25 @@ export default [
applyTheme(args[0]) applyTheme(args[0])
}, },
}, },
{
action: IRPCActionType.THEME_READ_THEME,
handler: async (_: IIPCEvent, args: [fileName: string]) => {
const abFilePath = path.join(themesDir(), args[0])
if (!fs.existsSync(abFilePath)) {
return null
}
return fs.readFileSync(abFilePath, 'utf-8')
},
type: IRPCType.INVOKE,
},
{
action: IRPCActionType.THEME_WRITE_THEME,
handler: async (_: IIPCEvent, args: [fileName: string, content: string]) => {
const abFilePath = path.join(themesDir(), args[0])
fs.ensureDirSync(path.dirname(abFilePath))
fs.writeFileSync(abFilePath, args[1], 'utf-8')
},
},
{ {
action: IRPCActionType.THEME_RESOLVE_THEMES, action: IRPCActionType.THEME_RESOLVE_THEMES,
handler: async () => { handler: async () => {

View File

@@ -75,11 +75,14 @@ export const IRPCActionType = {
GET_SYSTEM_THEME: 'GET_SYSTEM_THEME', GET_SYSTEM_THEME: 'GET_SYSTEM_THEME',
SET_SYSTEM_THEME: 'SET_SYSTEM_THEME', SET_SYSTEM_THEME: 'SET_SYSTEM_THEME',
APPLY_THEME: 'APPLY_THEME', APPLY_THEME: 'APPLY_THEME',
THEME_READ_THEME: 'THEME_READ_THEME',
THEME_WRITE_THEME: 'THEME_WRITE_THEME',
THEME_RESOLVE_THEMES: 'THEME_RESOLVE_THEMES', THEME_RESOLVE_THEMES: 'THEME_RESOLVE_THEMES',
THEME_FETCH_THEMES: 'THEME_FETCH_THEMES', THEME_FETCH_THEMES: 'THEME_FETCH_THEMES',
THEME_IMPORT_THEMES: 'THEME_IMPORT_THEMES', THEME_IMPORT_THEMES: 'THEME_IMPORT_THEMES',
THEME_APPLY_THEME: 'THEME_APPLY_THEME', THEME_APPLY_THEME: 'THEME_APPLY_THEME',
THEME_GET_BOOTSTRAP: 'THEME_GET_BOOTSTRAP', THEME_GET_BOOTSTRAP: 'THEME_GET_BOOTSTRAP',
RELOAD_APP: 'RELOAD_APP', RELOAD_APP: 'RELOAD_APP',
OPEN_URL: 'OPEN_URL', OPEN_URL: 'OPEN_URL',
OPEN_FILE: 'OPEN_FILE', OPEN_FILE: 'OPEN_FILE',

View File

@@ -4,6 +4,7 @@
<script setup> <script setup>
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands' import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
import { css } from '@codemirror/lang-css'
import { javascript } from '@codemirror/lang-javascript' import { javascript } from '@codemirror/lang-javascript'
import { json } from '@codemirror/lang-json' import { json } from '@codemirror/lang-json'
import { openSearchPanel, search, searchKeymap } from '@codemirror/search' import { openSearchPanel, search, searchKeymap } from '@codemirror/search'
@@ -11,6 +12,7 @@ import { EditorState } from '@codemirror/state'
import { oneDark } from '@codemirror/theme-one-dark' import { oneDark } from '@codemirror/theme-one-dark'
import { EditorView, keymap, lineNumbers } from '@codemirror/view' import { EditorView, keymap, lineNumbers } from '@codemirror/view'
import { onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue' import { onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue'
const props = defineProps({ const props = defineProps({
modelValue: { type: String, default: '' }, modelValue: { type: String, default: '' },
language: { type: String, default: 'javascript' }, language: { type: String, default: 'javascript' },
@@ -21,7 +23,7 @@ const editorRef = ref(null)
const view = shallowRef(null) const view = shallowRef(null)
onMounted(() => { onMounted(() => {
const languageExtension = props.language === 'json' ? json() : javascript() const languageExtension = props.language === 'json' ? json() : props.language === 'css' ? css() : javascript()
const startState = EditorState.create({ const startState = EditorState.create({
doc: props.modelValue, doc: props.modelValue,
extensions: [ extensions: [

View File

@@ -906,6 +906,7 @@
"downloadThemes": "Download Themes", "downloadThemes": "Download Themes",
"downloadThemesFailed": "Failed to download themes", "downloadThemesFailed": "Failed to download themes",
"downloadThemesSuccess": "Themes downloaded successfully", "downloadThemesSuccess": "Themes downloaded successfully",
"editTheme": "Edit Theme",
"enableAdvancedAnimation": "Enable Advanced Animation", "enableAdvancedAnimation": "Enable Advanced Animation",
"enableAdvancedAnimationDesc": "Do not enable this option on low-performance devices or when GPU acceleration is disabled", "enableAdvancedAnimationDesc": "Do not enable this option on low-performance devices or when GPU acceleration is disabled",
"hideDockHint": "Cannot hide both dock and tray at the same time", "hideDockHint": "Cannot hide both dock and tray at the same time",
@@ -1207,15 +1208,6 @@
"title": "Configurations" "title": "Configurations"
} }
}, },
"scripts": {
"createScript": "Create Script",
"deleteScript": "Delete Script",
"duplicateScriptNameError": "Script name already exists",
"editScripts": "Edit Script",
"newScriptTitle": "New Script",
"noScriptsFound": "No Scripts Found",
"pleaseEnterScriptName": "Please enter script name"
},
"settings": { "settings": {
"theme": { "theme": {
"auto": "Auto", "auto": "Auto",

View File

@@ -906,8 +906,10 @@
"downloadThemes": "下载主题", "downloadThemes": "下载主题",
"downloadThemesFailed": "下载主题失败", "downloadThemesFailed": "下载主题失败",
"downloadThemesSuccess": "主题下载成功", "downloadThemesSuccess": "主题下载成功",
"editTheme": "编辑主题",
"enableAdvancedAnimation": "启用高级动画效果", "enableAdvancedAnimation": "启用高级动画效果",
"enableAdvancedAnimationDesc": "不要在低性能设备上或关闭GPU加速时启用此选项", "enableAdvancedAnimationDesc": "不要在低性能设备上或关闭GPU加速时启用此选项",
"getThemeContentFailed": "获取主题内容失败",
"hideDockHint": "不支持同时隐藏 dock 和托盘", "hideDockHint": "不支持同时隐藏 dock 和托盘",
"importThemes": "导入主题", "importThemes": "导入主题",
"importThemesFailed": "导入主题失败", "importThemesFailed": "导入主题失败",

View File

@@ -906,8 +906,10 @@
"downloadThemes": "下載主題", "downloadThemes": "下載主題",
"downloadThemesFailed": "下載主題失敗", "downloadThemesFailed": "下載主題失敗",
"downloadThemesSuccess": "主題下載成功", "downloadThemesSuccess": "主題下載成功",
"editTheme": "編輯主題",
"enableAdvancedAnimation": "啟用高級動畫效果", "enableAdvancedAnimation": "啟用高級動畫效果",
"enableAdvancedAnimationDesc": "不要在低性能設備上或關閉GPU加速時啟用此選項", "enableAdvancedAnimationDesc": "不要在低性能設備上或關閉GPU加速時啟用此選項",
"getThemeContentFailed": "獲取主題內容失敗",
"hideDockHint": "不支持同時隱藏 dock 和托盤", "hideDockHint": "不支持同時隱藏 dock 和托盤",
"importThemes": "導入主題", "importThemes": "導入主題",
"importThemesFailed": "導入主題失敗", "importThemesFailed": "導入主題失敗",
@@ -1207,15 +1209,6 @@
"title": "配置" "title": "配置"
} }
}, },
"scripts": {
"createScript": "創建腳本",
"deleteScript": "刪除腳本",
"duplicateScriptNameError": "腳本名稱已存在",
"editScripts": "編輯腳本",
"newScriptTitle": "新建腳本",
"noScriptsFound": "未找到腳本",
"pleaseEnterScriptName": "請輸入腳本名稱"
},
"settings": { "settings": {
"theme": { "theme": {
"auto": "自動", "auto": "自動",

View File

@@ -86,36 +86,48 @@
</SettingCard> </SettingCard>
<SettingCard> <SettingCard>
<CustomSelect <SingleSelect
v-model="currentTheme" v-model="currentTheme"
:select-list="themeList"
:title="t('pages.settings.system.chooseTheme')" :title="t('pages.settings.system.chooseTheme')"
:icon="ImageIcon" :fronticon="false"
/> :key-list="themeList.map(item => item.value)"
:placeholder="themeList.find(theme => theme.value === currentTheme)?.label || ''"
>
<template #item="{ item }">
{{ themeList.find(theme => theme.value === item)?.label || item }}
</template>
</SingleSelect>
<template #extra>
<div class="mt-3 flex gap-4">
<CustomButton
:disabled="downloadingThemes"
:text="
downloadingThemes
? t('pages.settings.system.downloadingThemes')
: t('pages.settings.system.downloadThemes')
"
:icon-size="14"
:icon="Download"
type="secondary"
@click="handleDownloadThemes"
/>
<CustomButton
:icon="Import"
:text="t('pages.settings.system.importThemes')"
type="secondary"
:icon-size="14"
@click="handleImportThemes"
/>
<CustomButton
:icon="Edit2"
:text="t('pages.settings.system.editTheme')"
type="primary"
:icon-size="14"
@click="handleEditTheme"
/>
</div>
</template>
</SettingCard> </SettingCard>
<template #extra>
<div class="mt-3 flex gap-4">
<CustomButton
:disabled="downloadingThemes"
:text="
downloadingThemes
? t('pages.settings.system.downloadingThemes')
: t('pages.settings.system.downloadThemes')
"
:icon-size="14"
:icon="Download"
type="secondary"
@click="handleDownloadThemes"
/>
<CustomButton
:icon="Import"
:text="t('pages.settings.system.importThemes')"
type="secondary"
:icon-size="14"
@click="handleImportThemes"
/>
</div>
</template>
</SettingSection> </SettingSection>
<!-- Window Behavior Section --> <!-- Window Behavior Section -->
@@ -1219,7 +1231,7 @@
</CustomModal> </CustomModal>
<CustomModal v-if="editorVisible" v-model:visible="editorVisible" :title="t('common.edit')"> <CustomModal v-if="editorVisible" v-model:visible="editorVisible" :title="t('common.edit')">
<Editor v-model="editorContent" language="json" /> <Editor v-model="editorContent" :language="editorLanguage" />
<template #footer> <template #footer>
<CustomButton type="secondary" :text="t('common.cancel')" @click="editorVisible = false" /> <CustomButton type="secondary" :text="t('common.cancel')" @click="editorVisible = false" />
<CustomButton type="primary" :text="t('common.save')" @click="saveEditorContent" /> <CustomButton type="primary" :text="t('common.save')" @click="saveEditorContent" />
@@ -1236,6 +1248,7 @@ import {
CloudUpload, CloudUpload,
Download, Download,
Edit, Edit,
Edit2,
FileText, FileText,
FolderOpen, FolderOpen,
GitBranch, GitBranch,
@@ -1269,6 +1282,7 @@ import MultiSelect from '@/components/common/MultiSelect.vue'
import placeholderTable from '@/components/common/PlaceholderTable.vue' import placeholderTable from '@/components/common/PlaceholderTable.vue'
import SettingCard from '@/components/common/SettingCard.vue' import SettingCard from '@/components/common/SettingCard.vue'
import SettingSection from '@/components/common/SettingSection.vue' import SettingSection from '@/components/common/SettingSection.vue'
import SingleSelect from '@/components/common/SingleSelect.vue'
import Editor from '@/components/Editor.vue' import Editor from '@/components/Editor.vue'
import ImageProcessSetting from '@/components/ImageProcessSetting.vue' import ImageProcessSetting from '@/components/ImageProcessSetting.vue'
import useConfirm from '@/hooks/useConfirm' import useConfirm from '@/hooks/useConfirm'
@@ -1311,6 +1325,8 @@ const upDownConfigVisible = ref(false)
const proxyVisible = ref(false) const proxyVisible = ref(false)
const editorVisible = ref(false) const editorVisible = ref(false)
const editorContent = ref('// 在这里开始编写代码...\nfunction hello() {\n console.log("Hello Electron!");\n}') const editorContent = ref('// 在这里开始编写代码...\nfunction hello() {\n console.log("Hello Electron!");\n}')
const editorLanguage = ref('json')
const currentEditFile = ref('')
const latestVersion = ref('') const latestVersion = ref('')
const releaseNotes = ref('') const releaseNotes = ref('')
@@ -1430,6 +1446,21 @@ const logLevel = [
const syncType = ['github', 'gitee', 'gitea', 'webdav'] const syncType = ['github', 'gitee', 'gitea', 'webdav']
const version = pkg.version const version = pkg.version
const buildInThemesList = [
'adwaita.css',
'anime.css',
'bilibili.css',
'Catppucin.css',
'CoolApk.css',
'Cupertino.css',
'default.css',
'goldensand.css',
'Huorong.css',
'purple.css',
'wechat.css',
'win11.css',
]
const RELEASE_NOTES_CACHE_DURATION = 30 * 60 * 1000 const RELEASE_NOTES_CACHE_DURATION = 30 * 60 * 1000
const shortUrlServerList = [ const shortUrlServerList = [
@@ -1747,6 +1778,19 @@ async function handleImportThemes() {
} }
} }
async function handleEditTheme() {
try {
const themeContent = await window.electron.triggerRPC<string>(IRPCActionType.THEME_READ_THEME, currentTheme.value)
editorContent.value = themeContent || ''
currentEditFile.value = currentTheme.value
editorLanguage.value = 'css'
editorVisible.value = true
} catch (error) {
console.error('Failed to open theme folder:', error)
message.error(t('pages.settings.system.getThemeContentFailed'))
}
}
async function handleThemeChange(theme: string) { async function handleThemeChange(theme: string) {
try { try {
await window.electron.triggerRPC(IRPCActionType.THEME_APPLY_THEME, theme) await window.electron.triggerRPC(IRPCActionType.THEME_APPLY_THEME, theme)
@@ -1842,41 +1886,58 @@ async function handleChangeSecondPicBed() {
window.electron.sendRPC(IRPCActionType.SHOW_SECOND_UPLOADER_MENU) window.electron.sendRPC(IRPCActionType.SHOW_SECOND_UPLOADER_MENU)
} }
async function saveEditorContent() {
const content = editorContent.value.trim()
await saveFile('data.json', content, 'json')
editorVisible.value = false
}
async function openFile(file: string) { async function openFile(file: string) {
window.electron.sendRPC(IRPCActionType.PICLIST_OPEN_FILE, file) window.electron.sendRPC(IRPCActionType.PICLIST_OPEN_FILE, file)
} }
async function editFile(file: string, mode: 'text' | 'json' = 'text') { async function editFile(file: string) {
const content = (await window.electron.triggerRPC<string>(IRPCActionType.READ_FILE_CONTENT, file)) || '' const content = (await window.electron.triggerRPC<string>(IRPCActionType.READ_FILE_CONTENT, file)) || ''
if (mode === 'json') { try {
try { editorContent.value = JSON.stringify(JSON.parse(content), null, 2)
editorContent.value = JSON.stringify(JSON.parse(content), null, 2) } catch (error) {
} catch (error) {
editorContent.value = content
}
} else {
editorContent.value = content editorContent.value = content
} }
currentEditFile.value = file
editorLanguage.value = 'json'
editorVisible.value = true editorVisible.value = true
} }
async function saveFile(file: string, content: string, mode: 'text' | 'json' = 'text') { async function saveEditorContent() {
let dataToSave = content if (currentEditFile.value === 'data.json' || currentEditFile.value === 'manage.json') {
if (mode === 'json') { const content = editorContent.value.trim()
await saveFile(currentEditFile.value, content)
} else if (currentEditFile.value.endsWith('.css')) {
try { try {
dataToSave = JSON.stringify(JSON.parse(content), null, 2) let themeFileName
if (buildInThemesList.includes(currentTheme.value)) {
themeFileName = `custom-${currentTheme.value}`
} else {
themeFileName = currentTheme.value
}
window.electron.sendRPC(IRPCActionType.THEME_WRITE_THEME, themeFileName, editorContent.value)
message.success(t('pages.settings.advanced.saveFileSuccess'))
setTimeout(async () => {
await loadThemes()
await window.electron.triggerRPC(IRPCActionType.THEME_APPLY_THEME, themeFileName)
}, 1000)
} catch (error) { } catch (error) {
console.error('Invalid JSON content:', error) console.error('Failed to save theme:', error)
message.error(t('pages.settings.advanced.invalidJson')) message.error(t('pages.settings.advanced.saveFileFailed'))
return
} }
} }
editorVisible.value = false
}
async function saveFile(file: string, content: string) {
let dataToSave = content
try {
dataToSave = JSON.stringify(JSON.parse(content), null, 2)
} catch (error) {
console.error('Invalid JSON content:', error)
message.error(t('pages.settings.advanced.invalidJson'))
return
}
try { try {
window.electron.sendRPC(IRPCActionType.WRITE_FILE_CONTENT, file, dataToSave) window.electron.sendRPC(IRPCActionType.WRITE_FILE_CONTENT, file, dataToSave)
message.success(t('pages.settings.advanced.saveFileSuccess')) message.success(t('pages.settings.advanced.saveFileSuccess'))

View File

@@ -163,6 +163,11 @@
:title="t('pages.scripts.selectScriptType')" :title="t('pages.scripts.selectScriptType')"
:key-list="supportedScriptCategories.map(cat => cat.type)" :key-list="supportedScriptCategories.map(cat => cat.type)"
:fronticon="false" :fronticon="false"
:placeholder="
supportedScriptCategories.find(cat => cat.type === newScriptCategory)
? supportedScriptCategories.find(cat => cat.type === newScriptCategory)?.name
: newScriptCategory
"
> >
<template #item="{ item }"> <template #item="{ item }">
{{ {{

View File

@@ -23,6 +23,8 @@ export const IRPCActionType = {
OPEN_FILE: 'OPEN_FILE', OPEN_FILE: 'OPEN_FILE',
HIDE_DOCK: 'HIDE_DOCK', HIDE_DOCK: 'HIDE_DOCK',
SET_CURRENT_LANGUAGE: 'SET_CURRENT_LANGUAGE', SET_CURRENT_LANGUAGE: 'SET_CURRENT_LANGUAGE',
THEME_READ_THEME: 'THEME_READ_THEME',
THEME_WRITE_THEME: 'THEME_WRITE_THEME',
THEME_RESOLVE_THEMES: 'THEME_RESOLVE_THEMES', THEME_RESOLVE_THEMES: 'THEME_RESOLVE_THEMES',
THEME_FETCH_THEMES: 'THEME_FETCH_THEMES', THEME_FETCH_THEMES: 'THEME_FETCH_THEMES',
THEME_IMPORT_THEMES: 'THEME_IMPORT_THEMES', THEME_IMPORT_THEMES: 'THEME_IMPORT_THEMES',

View File

@@ -1017,6 +1017,17 @@
"@codemirror/view" "^6.27.0" "@codemirror/view" "^6.27.0"
"@lezer/common" "^1.1.0" "@lezer/common" "^1.1.0"
"@codemirror/lang-css@^6.3.1":
version "6.3.1"
resolved "https://registry.yarnpkg.com/@codemirror/lang-css/-/lang-css-6.3.1.tgz#763ca41aee81bb2431be55e3cfcc7cc8e91421a3"
integrity sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==
dependencies:
"@codemirror/autocomplete" "^6.0.0"
"@codemirror/language" "^6.0.0"
"@codemirror/state" "^6.0.0"
"@lezer/common" "^1.0.2"
"@lezer/css" "^1.1.7"
"@codemirror/lang-javascript@^6.2.4": "@codemirror/lang-javascript@^6.2.4":
version "6.2.4" version "6.2.4"
resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz#eef2227d1892aae762f3a0f212f72bec868a02c5" resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz#eef2227d1892aae762f3a0f212f72bec868a02c5"
@@ -2630,11 +2641,20 @@
resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.1.1.tgz#0c01dd3a3483882af7cf3878d4e71d505c81fc4a" resolved "https://registry.yarnpkg.com/@keyv/serialize/-/serialize-1.1.1.tgz#0c01dd3a3483882af7cf3878d4e71d505c81fc4a"
integrity sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA== integrity sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==
"@lezer/common@^1.0.0", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.3.0", "@lezer/common@^1.5.0": "@lezer/common@^1.0.0", "@lezer/common@^1.0.2", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0", "@lezer/common@^1.3.0", "@lezer/common@^1.5.0":
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.5.0.tgz#db227b596260189b67ba286387d9dc81fb07c70b" resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.5.0.tgz#db227b596260189b67ba286387d9dc81fb07c70b"
integrity sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA== integrity sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==
"@lezer/css@^1.1.7":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@lezer/css/-/css-1.3.0.tgz#296f298814782c2fad42a936f3510042cdcd2034"
integrity sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==
dependencies:
"@lezer/common" "^1.2.0"
"@lezer/highlight" "^1.0.0"
"@lezer/lr" "^1.3.0"
"@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3": "@lezer/highlight@^1.0.0", "@lezer/highlight@^1.1.3":
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.3.tgz#a20f324b71148a2ea9ba6ff42e58bbfaec702857" resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.3.tgz#a20f324b71148a2ea9ba6ff42e58bbfaec702857"