87 lines
2.6 KiB
Vue
87 lines
2.6 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref } from 'vue'
|
|
import { Textarea } from '@/components/ui/textarea'
|
|
import { Label } from '@/components/ui/label'
|
|
import Segmented from '../components/Segmented.vue'
|
|
import ResultArea from '../components/ResultArea.vue'
|
|
|
|
type CaseMode =
|
|
| 'camel' | 'pascal' | 'snake' | 'kebab'
|
|
| 'upper' | 'lower' | 'title'
|
|
| 'spaceToDash' | 'trimLines' | 'collapseSpace'
|
|
|
|
const modes: { value: CaseMode; label: string }[] = [
|
|
{ value: 'camel', label: 'camelCase' },
|
|
{ value: 'pascal', label: 'PascalCase' },
|
|
{ value: 'snake', label: 'snake_case' },
|
|
{ value: 'kebab', label: 'kebab-case' },
|
|
{ value: 'upper', label: '全大写' },
|
|
{ value: 'lower', label: '全小写' },
|
|
{ value: 'title', label: '标题式' },
|
|
{ value: 'spaceToDash', label: '空格转下划线' },
|
|
{ value: 'collapseSpace', label: '合并空行空白' },
|
|
{ value: 'trimLines', label: '每行去首尾空格' }
|
|
]
|
|
|
|
const mode = ref<CaseMode>('camel')
|
|
const input = ref('')
|
|
|
|
function toWords(s: string): string[] {
|
|
// 拆分 camelCase / snake_case / kebab-case / 空格,得到词
|
|
return s
|
|
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
.replace(/[_\-\s]+/g, ' ')
|
|
.trim()
|
|
.split(' ')
|
|
.filter(Boolean)
|
|
}
|
|
|
|
const output = computed(() => {
|
|
const v = input.value
|
|
if (!v) return ''
|
|
switch (mode.value) {
|
|
case 'upper':
|
|
return v.toUpperCase()
|
|
case 'lower':
|
|
return v.toLowerCase()
|
|
case 'title':
|
|
return v.replace(/\b\w/g, ch => ch.toUpperCase())
|
|
case 'spaceToDash':
|
|
return v.replace(/\s+/g, '_')
|
|
case 'collapseSpace':
|
|
return v.split(/\n+/).map(l => l.trim()).filter(Boolean).join('\n')
|
|
case 'trimLines':
|
|
return v.split('\n').map(l => l.trim()).join('\n')
|
|
case 'camel': // fallthrough
|
|
case 'pascal':
|
|
case 'snake':
|
|
case 'kebab':
|
|
break
|
|
}
|
|
const words = toWords(v).filter(Boolean)
|
|
if (words.length === 0) return ''
|
|
if (mode.value === 'camel') {
|
|
return words[0].toLowerCase() + words.slice(1).map(w => cap(w)).join('')
|
|
}
|
|
if (mode.value === 'pascal') {
|
|
return words.map(cap).join('')
|
|
}
|
|
const sep = mode.value === 'snake' ? '_' : '-'
|
|
return words.map(w => w.toLowerCase()).join(sep)
|
|
})
|
|
|
|
function cap(w: string): string {
|
|
return w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col gap-4">
|
|
<Segmented v-model="mode" :options="modes" />
|
|
<div class="flex flex-col gap-1.5">
|
|
<Label class="text-xs">原文</Label>
|
|
<Textarea v-model="input" placeholder="在此输入..." class="min-h-[140px] font-mono text-xs resize-y" />
|
|
</div>
|
|
<ResultArea :text="output" placeholder="结果" />
|
|
</div>
|
|
</template> |