valaxy 0.28.0 → 0.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ <script lang="ts" setup>
2
+ import type { LocalSearchResult } from '../composables/search/useLocalSearch'
3
+ import { ref, watch } from 'vue'
4
+ import { useRouter } from 'vue-router'
5
+ import { useLocalSearch } from '../composables/search/useLocalSearch'
6
+
7
+ const props = defineProps<{
8
+ open: boolean
9
+ }>()
10
+
11
+ const emit = defineEmits<{
12
+ (e: 'close'): void
13
+ }>()
14
+
15
+ const query = ref('')
16
+ const { results, loading, load } = useLocalSearch(query)
17
+ const selectedIndex = ref(0)
18
+
19
+ const router = useRouter()
20
+
21
+ watch(() => props.open, (val) => {
22
+ if (val) {
23
+ load()
24
+ selectedIndex.value = 0
25
+ }
26
+ else {
27
+ query.value = ''
28
+ }
29
+ })
30
+
31
+ watch(results, () => {
32
+ selectedIndex.value = 0
33
+ })
34
+
35
+ function getPageTitle(id: string): string {
36
+ return id.replace(/#.*$/, '').replace(/\.html$/, '') || '/'
37
+ }
38
+
39
+ function getSectionTitle(result: LocalSearchResult): string {
40
+ return [...result.titles, result.title].filter(Boolean).join(' > ')
41
+ }
42
+
43
+ function navigate(result: LocalSearchResult) {
44
+ const url = result.id
45
+ router.push(url)
46
+ emit('close')
47
+ }
48
+
49
+ function updateQuery(value: string) {
50
+ query.value = value
51
+ }
52
+
53
+ function onKeydown(e: KeyboardEvent) {
54
+ switch (e.key) {
55
+ case 'ArrowDown':
56
+ e.preventDefault()
57
+ selectedIndex.value = Math.min(selectedIndex.value + 1, results.value.length - 1)
58
+ break
59
+ case 'ArrowUp':
60
+ e.preventDefault()
61
+ selectedIndex.value = Math.max(selectedIndex.value - 1, 0)
62
+ break
63
+ case 'Enter':
64
+ e.preventDefault()
65
+ if (results.value[selectedIndex.value]) {
66
+ navigate(results.value[selectedIndex.value])
67
+ }
68
+ break
69
+ case 'Escape':
70
+ e.preventDefault()
71
+ emit('close')
72
+ break
73
+ }
74
+ }
75
+ </script>
76
+
77
+ <template>
78
+ <slot
79
+ :query="query"
80
+ :results="results"
81
+ :loading="loading"
82
+ :selected-index="selectedIndex"
83
+ :update-query="updateQuery"
84
+ :navigate="navigate"
85
+ :on-keydown="onKeydown"
86
+ :get-page-title="getPageTitle"
87
+ :get-section-title="getSectionTitle"
88
+ />
89
+ </template>
@@ -28,7 +28,7 @@ import valaxyLogoPng from '../assets/images/valaxy-logo.png'
28
28
  max-width: 350px;
29
29
  width: 150%;
30
30
  height: 150%;
31
- background-image: linear-gradient(-45deg, rgb(108, 34, 236) 50%, rgba(59,130,246,var(--un-to-opacity, 1)) 50%);
31
+ background-image: linear-gradient(-45deg, rgb(108 34 236) 50%, rgb(59 130 246 / var(--un-to-opacity, 1)) 50%);
32
32
  opacity: 0.3;
33
33
  transition: opacity var(--va-transition-duration-fast);
34
34
  }
@@ -74,7 +74,7 @@ function jumpTo(page: number) {
74
74
 
75
75
  <style lang="scss">
76
76
  :root {
77
- --page-btn-bg-color: rgba(255, 255, 255, 0.5);
77
+ --page-btn-bg-color: rgb(255 255 255 / 0.5);
78
78
  --page-btn-hover-bg-color: var(--va-c-primary-lighter);
79
79
  --page-btn-active-bg-color: var(--va-c-primary-light);
80
80
  }
@@ -166,7 +166,6 @@ export function mergeCollapsedCollections(
166
166
 
167
167
  /**
168
168
  * get post list in 'pages/posts' folder
169
- * todo: use vue provide/inject to global
170
169
  */
171
170
  export function usePostList(params: {
172
171
  type?: string
@@ -1 +1,2 @@
1
1
  export * from './useFuseSearch'
2
+ export * from './useLocalSearch'
@@ -0,0 +1,53 @@
1
+ import type MiniSearch from 'minisearch'
2
+ import type { Ref } from 'vue'
3
+ import { ref, shallowRef, watchEffect } from 'vue'
4
+
5
+ export interface LocalSearchResult {
6
+ id: string
7
+ score: number
8
+ terms: string[]
9
+ title: string
10
+ titles: string[]
11
+ }
12
+
13
+ export function useLocalSearch(query: Ref<string>) {
14
+ const results = shallowRef<LocalSearchResult[]>([])
15
+ const loading = ref(false)
16
+ let miniSearch: MiniSearch | null = null
17
+
18
+ async function load(locale = 'root') {
19
+ loading.value = true
20
+ try {
21
+ const searchIndex = (await import('@localSearchIndex')).default
22
+ const loader = searchIndex[locale] ?? searchIndex[Object.keys(searchIndex)[0]]
23
+ if (!loader) {
24
+ loading.value = false
25
+ return
26
+ }
27
+ const mod = await loader()
28
+ const data: string = JSON.parse(mod.default)
29
+ const { default: MiniSearchCtor } = await import('minisearch')
30
+ miniSearch = MiniSearchCtor.loadJSON(data, {
31
+ fields: ['title', 'titles', 'text'],
32
+ storeFields: ['title', 'titles'],
33
+ })
34
+ }
35
+ finally {
36
+ loading.value = false
37
+ }
38
+ }
39
+
40
+ watchEffect(() => {
41
+ if (!miniSearch || !query.value.trim()) {
42
+ results.value = []
43
+ return
44
+ }
45
+ results.value = miniSearch.search(query.value, {
46
+ prefix: true,
47
+ fuzzy: 0.2,
48
+ boost: { title: 4, text: 2, titles: 1 },
49
+ }) as unknown as LocalSearchResult[]
50
+ })
51
+
52
+ return { results, loading, load }
53
+ }
@@ -26,6 +26,6 @@ const { back } = useBack()
26
26
  // inspired by https://codepen.io/pgalor/pen/OeRWJQ
27
27
  .not-found {
28
28
  font-size: 10rem;
29
- text-shadow: 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
29
+ text-shadow: 0 5px 10px rgb(0 0 0 / .25), 0 20px 20px rgb(0 0 0 / .15);
30
30
  }
31
31
  </style>
@@ -92,9 +92,12 @@ category:
92
92
 
93
93
  search:
94
94
  placeholder: Searching...
95
+ loading: Loading...
95
96
  empty: 'We could not find any results for the search: {query}.'
96
97
  hits_time: '{hits} results found in {time} ms'
97
98
  hits: '{count} results found'
99
+ no_results: No results found
100
+ no_results_hint: Try adjusting your search terms
98
101
 
99
102
  symbol:
100
103
  comma: ', '
@@ -91,9 +91,12 @@ category:
91
91
 
92
92
  search:
93
93
  placeholder: 搜索...
94
+ loading: 加载中...
94
95
  empty: '找不到您查询的内容: {query}'
95
96
  hits_time: '找到 {hits} 条结果(用时 {time} 毫秒)'
96
97
  hits: '找到 {count} 条结果'
98
+ no_results: 未找到相关结果
99
+ no_results_hint: 请尝试调整搜索关键词
97
100
 
98
101
  symbol:
99
102
  comma: ,
@@ -1,6 +1,5 @@
1
1
  import type { ValaxySSGContext } from '../setups'
2
2
 
3
- import { defineAsyncComponent } from 'vue'
4
3
  import AppLink from '../components/AppLink.vue'
5
4
  import ValaxyTranslate from '../components/builtin/ValaxyTranslate.vue'
6
5
 
@@ -11,10 +10,4 @@ import ValaxyTranslate from '../components/builtin/ValaxyTranslate.vue'
11
10
  export function registerGlobalComponents(ctx: ValaxySSGContext) {
12
11
  ctx.app.component('AppLink', AppLink)
13
12
  ctx.app.component('VT', ValaxyTranslate)
14
-
15
- // DEV-only: register ValaxyDebug component (tree-shaken in production)
16
- if (import.meta.env.DEV) {
17
- const ValaxyDebug = defineAsyncComponent(() => import('../components/.exclude/ValaxyDebug.vue'))
18
- ctx.app.component('ValaxyDebug', ValaxyDebug)
19
- }
20
13
  }
package/client/shims.d.ts CHANGED
@@ -37,6 +37,11 @@ declare module '#valaxy/styles' {
37
37
  export default styles
38
38
  }
39
39
 
40
+ declare module '@localSearchIndex' {
41
+ const index: Record<string, () => Promise<{ default: string }>>
42
+ export default index
43
+ }
44
+
40
45
  // valaxy features
41
46
  declare module '#valaxy/blog/collections' {
42
47
  import type { CollectionConfig } from './types'
@@ -58,7 +58,7 @@ html:not(.dark) .vp-code-dark {
58
58
  white-space: pre;
59
59
  word-spacing: normal;
60
60
  word-break: normal;
61
- word-wrap: normal;
61
+ overflow-wrap: normal;
62
62
  tab-size: 4;
63
63
  hyphens: none;
64
64
  }
@@ -4,4 +4,4 @@
4
4
  @use "./transition.scss" as *;
5
5
 
6
6
  // markdown
7
- @use "./markdown.scss";
7
+ @use "./markdown";
@@ -1,7 +1,6 @@
1
1
  @use "sass:map";
2
2
 
3
3
  .markdown-body {
4
-
5
4
  h1,
6
5
  h2,
7
6
  h3,
@@ -52,27 +52,26 @@ html.dark {
52
52
  * - `text-3`: Used for subtle texts, such as "placeholders" or "caret icon".
53
53
  * -------------------------------------------------------------------------- */
54
54
  :root {
55
- --va-c-text-1: rgba(60, 60, 67);
56
- --va-c-text-2: rgba(60, 60, 67, 0.78);
57
- --va-c-text-3: rgba(60, 60, 67, 0.56);
55
+ --va-c-text-1: rgb(60 60 67);
56
+ --va-c-text-2: rgb(60 60 67 / 0.78);
57
+ --va-c-text-3: rgb(60 60 67 / 0.56);
58
58
  }
59
59
 
60
60
  .dark {
61
- --va-c-text-1: rgba(255, 255, 245, 0.86);
62
- --va-c-text-2: rgba(235, 235, 245, 0.6);
63
- --va-c-text-3: rgba(235, 235, 245, 0.38);
61
+ --va-c-text-1: rgb(255 255 245 / 0.86);
62
+ --va-c-text-2: rgb(235 235 245 / 0.6);
63
+ --va-c-text-3: rgb(235 235 245 / 0.38);
64
64
  }
65
65
 
66
66
  // bg
67
67
  :root {
68
- --va-c-bg: #ffffff;
69
- --va-c-bg-light: #ffffff;
68
+ --va-c-bg: #fff;
69
+ --va-c-bg-light: #fff;
70
70
  --va-c-bg-dark: #fafafa;
71
- --va-c-bg-opacity: rgba(255, 255, 255, 0.8);
71
+ --va-c-bg-opacity: rgb(255 255 255 / 0.8);
72
72
  --va-c-bg-soft: #f9f9f9;
73
73
  --va-c-bg-alt: #f9f9f9;
74
74
  --va-c-bg-mute: #f1f1f1;
75
-
76
75
  --va-c-bg-elevated: #f9f9f9;
77
76
  }
78
77
 
@@ -80,11 +79,10 @@ html.dark {
80
79
  --va-c-bg: #1a1a1d;
81
80
  --va-c-bg-light: #202127;
82
81
  --va-c-bg-dark: #1a1a1a;
83
- --va-c-bg-opacity: rgba(0, 0, 0, 0.8);
82
+ --va-c-bg-opacity: rgb(0 0 0 / 0.8);
84
83
  --va-c-bg-alt: #161618;
85
84
  --va-c-bg-soft: #202127;
86
85
  --va-c-bg-mute: #2f2f2f;
87
-
88
86
  --va-c-bg-elevated: #202127;
89
87
  }
90
88
 
@@ -1,4 +1,4 @@
1
- @forward './config.scss';
2
- @forward './media.scss';
3
- @forward './size.scss';
4
- @forward './variable.scss';
1
+ @forward './config';
2
+ @forward './media';
3
+ @forward './size';
4
+ @forward './variable';
@@ -1,6 +1,5 @@
1
1
  .katex-display {
2
- overflow-x: auto;
3
- overflow-y: visible;
2
+ overflow: auto visible;
4
3
  padding: 8px 0;
5
4
  }
6
5
 
@@ -1,7 +1,7 @@
1
1
  import 'node:process';
2
2
  import 'yargs';
3
3
  import 'yargs/helpers';
4
- export { c as cli, I as registerDevCommand, W as run, Z as startValaxyDev } from '../../shared/valaxy.DQ6HsU2J.mjs';
4
+ export { c as cli, J as registerDevCommand, X as run, _ as startValaxyDev } from '../../shared/valaxy.Cbgd5gHB.mjs';
5
5
  import 'node:os';
6
6
  import 'node:path';
7
7
  import 'consola';
@@ -29,6 +29,7 @@ import 'feed';
29
29
  import 'markdown-it';
30
30
  import 'table';
31
31
  import 'hookable';
32
+ import 'node:fs';
32
33
  import 'node:child_process';
33
34
  import 'node:v8';
34
35
  import 'vite-ssg-sitemap';
@@ -57,7 +58,6 @@ import 'p-map';
57
58
  import 'node:buffer';
58
59
  import 'minisearch';
59
60
  import 'lru-cache';
60
- import 'node:fs';
61
61
  import 'jiti';
62
62
  import 'unocss';
63
63
  import 'pascalcase';
@@ -1,7 +1,7 @@
1
1
  import { ViteSSGOptions } from 'vite-ssg';
2
2
  import * as vite from 'vite';
3
3
  import { UserConfig, InlineConfig, ViteDevServer, PluginOption, Plugin } from 'vite';
4
- import { D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, S as SiteConfig, U as UserSiteConfig } from '../shared/valaxy.6MW2qn5T.mjs';
4
+ import { S as SiteConfig, D as DefaultTheme, R as RuntimeConfig, a as RedirectItem, V as ValaxyConfig, P as PartialDeep, b as ValaxyAddon, U as UserSiteConfig } from '../shared/valaxy.D8f6owDk.mjs';
5
5
  import Vue from '@vitejs/plugin-vue';
6
6
  import { Hookable } from 'hookable';
7
7
  import { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
@@ -445,6 +445,14 @@ interface ValaxyHooks {
445
445
  'md:afterRender': (ctx: MdAfterRenderContext) => HookResult;
446
446
  'build:before': () => HookResult;
447
447
  'build:after': () => HookResult;
448
+ /**
449
+ * Called to compute statistics (word count, reading time) for a markdown route.
450
+ * Default implementation uses `presetStatistics`; addons/themes can hook to override.
451
+ */
452
+ 'statistics': (ctx: {
453
+ route: EditableTreeNode;
454
+ options: SiteConfig['statistics'];
455
+ }) => HookResult;
448
456
  /**
449
457
  * @experimental
450
458
  * Called before content loaders start fetching.
@@ -975,10 +983,17 @@ declare function build(valaxyApp: ValaxyNode, viteConfig?: InlineConfig): Promis
975
983
  */
976
984
  declare function ssgBuildLegacy(valaxyApp: ValaxyNode, viteConfig?: InlineConfig): Promise<void>;
977
985
  /**
978
- * post process for ssg fix extra string like `/html>` `ml>` `l>`
979
- * handle tasks after ssg build
980
- * todo find why
981
- * @param options
986
+ * Fix corrupted HTML produced by vite-ssg's JSDOM serialization under memory
987
+ * pressure. JSDOM.serialize() can emit truncated trailing fragments
988
+ * (e.g. `/html>`, `ml>`, `l>`) when heap is constrained during
989
+ * high-concurrency renders.
990
+ *
991
+ * Only needed for the legacy vite-ssg engine; the built-in Valaxy SSG
992
+ * engine uses pure string rendering and is not affected.
993
+ */
994
+ declare function fixViteSsgHtml(options: ResolvedValaxyOptions): Promise<void>;
995
+ /**
996
+ * Shared post-processing after SSG build (both engines).
982
997
  */
983
998
  declare function postProcessForSSG(options: ResolvedValaxyOptions): Promise<void>;
984
999
  declare function generateClientRedirects(options: ResolvedValaxyOptions): Promise<void>;
@@ -1202,5 +1217,5 @@ declare function toAtFS(path: string): string;
1202
1217
  declare function resolveImportPath(importName: string, ensure?: true): Promise<string>;
1203
1218
  declare function resolveImportPath(importName: string, ensure?: boolean): Promise<string | undefined>;
1204
1219
 
1205
- export { $t, ALL_ROUTE, EXCERPT_SEPARATOR, GLOBAL_STATE, PATHNAME_PROTOCOL_RE, ViteValaxyPlugins, build, createServer, createValaxyPlugin, customElements, defaultSiteConfig, defaultValaxyConfig, defaultViteConfig, defineAddon, defineConfig, defineContentLoader, defineSiteConfig, defineTheme, defineUnoSetup, defineValaxyAddon, defineValaxyConfig, defineValaxyTheme, encryptContent, generateClientRedirects, getGitTimestamp, getIndexHtml, getServerInfoText, isExternal, isInstalledGlobally, isKatexEnabled, isKatexPluginNeeded, isMathJaxEnabled, isPath, loadConfigFromFile, mergeValaxyConfig, mergeViteConfigs, postProcessForSSG, processValaxyOptions, resolveAddonsConfig, resolveImportPath, resolveImportUrl, resolveOptions, resolveSiteConfig, resolveSiteConfigFromRoot, resolveThemeConfigFromRoot, resolveThemeValaxyConfig, resolveUserThemeConfig, resolveValaxyConfig, resolveValaxyConfigFromRoot, ssgBuild, ssgBuildLegacy, toAtFS, transformObject, version };
1220
+ export { $t, ALL_ROUTE, EXCERPT_SEPARATOR, GLOBAL_STATE, PATHNAME_PROTOCOL_RE, ViteValaxyPlugins, build, createServer, createValaxyPlugin, customElements, defaultSiteConfig, defaultValaxyConfig, defaultViteConfig, defineAddon, defineConfig, defineContentLoader, defineSiteConfig, defineTheme, defineUnoSetup, defineValaxyAddon, defineValaxyConfig, defineValaxyTheme, encryptContent, fixViteSsgHtml, generateClientRedirects, getGitTimestamp, getIndexHtml, getServerInfoText, isExternal, isInstalledGlobally, isKatexEnabled, isKatexPluginNeeded, isMathJaxEnabled, isPath, loadConfigFromFile, mergeValaxyConfig, mergeViteConfigs, postProcessForSSG, processValaxyOptions, resolveAddonsConfig, resolveImportPath, resolveImportUrl, resolveOptions, resolveSiteConfig, resolveSiteConfigFromRoot, resolveThemeConfigFromRoot, resolveThemeValaxyConfig, resolveUserThemeConfig, resolveValaxyConfig, resolveValaxyConfigFromRoot, ssgBuild, ssgBuildLegacy, toAtFS, transformObject, version };
1206
1221
  export type { CdnModule, ContentItem, ContentLoader, ContentLoaderContext, HookResult, LoadConfigFromFileOptions, MdAfterRenderContext, ResolvedConfig, ResolvedValaxyOptions, UnoSetup, UserInputConfig, UserValaxyNodeConfig, ValaxyAddonExport, ValaxyAddonFn, ValaxyAddonLike, ValaxyAddonResolver, ValaxyAddons, ValaxyApp, ValaxyConfigExport, ValaxyConfigExtendKey, ValaxyConfigFn, ValaxyEntryOptions, ValaxyExtendConfig, ValaxyHooks, ValaxyNode, ValaxyNodeConfig, ValaxyPickConfig, ValaxyServerOptions, ValaxyTheme };
@@ -1,5 +1,6 @@
1
- export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as generateClientRedirects, r as getGitTimestamp, s as getIndexHtml, t as getServerInfoText, u as isExternal, v as isInstalledGlobally, w as isKatexEnabled, x as isKatexPluginNeeded, y as isMathJaxEnabled, z as isPath, B as loadConfigFromFile, C as mergeValaxyConfig, D as mergeViteConfigs, F as postProcessForSSG, H as processValaxyOptions, I as registerDevCommand, J as resolveAddonsConfig, K as resolveImportPath, L as resolveImportUrl, M as resolveOptions, N as resolveSiteConfig, O as resolveSiteConfigFromRoot, Q as resolveThemeConfigFromRoot, R as resolveThemeValaxyConfig, S as resolveUserThemeConfig, T as resolveValaxyConfig, U as resolveValaxyConfigFromRoot, W as run, X as ssgBuild, Y as ssgBuildLegacy, Z as startValaxyDev, _ as toAtFS, $ as transformObject, a0 as version } from '../shared/valaxy.DQ6HsU2J.mjs';
1
+ export { A as ALL_ROUTE, E as EXCERPT_SEPARATOR, G as GLOBAL_STATE, P as PATHNAME_PROTOCOL_RE, V as ViteValaxyPlugins, b as build, c as cli, a as createServer, d as createValaxyPlugin, e as customElements, f as defaultSiteConfig, g as defaultValaxyConfig, h as defaultViteConfig, i as defineAddon, j as defineConfig, k as defineSiteConfig, l as defineTheme, m as defineValaxyAddon, n as defineValaxyConfig, o as defineValaxyTheme, p as encryptContent, q as fixViteSsgHtml, r as generateClientRedirects, s as getGitTimestamp, t as getIndexHtml, u as getServerInfoText, v as isExternal, w as isInstalledGlobally, x as isKatexEnabled, y as isKatexPluginNeeded, z as isMathJaxEnabled, B as isPath, C as loadConfigFromFile, D as mergeValaxyConfig, F as mergeViteConfigs, H as postProcessForSSG, I as processValaxyOptions, J as registerDevCommand, K as resolveAddonsConfig, L as resolveImportPath, M as resolveImportUrl, N as resolveOptions, O as resolveSiteConfig, Q as resolveSiteConfigFromRoot, R as resolveThemeConfigFromRoot, S as resolveThemeValaxyConfig, T as resolveUserThemeConfig, U as resolveValaxyConfig, W as resolveValaxyConfigFromRoot, X as run, Y as ssgBuild, Z as ssgBuildLegacy, _ as startValaxyDev, $ as toAtFS, a0 as transformObject, a1 as version } from '../shared/valaxy.Cbgd5gHB.mjs';
2
2
  import 'node:path';
3
+ import 'consola';
3
4
  import 'fs-extra';
4
5
  import 'consola/utils';
5
6
  import 'node:process';
@@ -7,7 +8,6 @@ import 'define-config-ts';
7
8
  import 'yargs';
8
9
  import 'yargs/helpers';
9
10
  import 'node:os';
10
- import 'consola';
11
11
  import 'fast-glob';
12
12
  import 'gray-matter';
13
13
  import 'js-yaml';
@@ -29,6 +29,7 @@ import 'feed';
29
29
  import 'markdown-it';
30
30
  import 'table';
31
31
  import 'hookable';
32
+ import 'node:fs';
32
33
  import 'node:child_process';
33
34
  import 'node:v8';
34
35
  import 'vite-ssg-sitemap';
@@ -57,7 +58,6 @@ import 'p-map';
57
58
  import 'node:buffer';
58
59
  import 'minisearch';
59
60
  import 'lru-cache';
60
- import 'node:fs';
61
61
  import 'jiti';
62
62
  import 'unocss';
63
63
  import 'pascalcase';