docs: 添加 caniuse 可视化配置工具

This commit is contained in:
pengzhanbo 2024-04-17 12:16:51 +08:00
parent f1570e49a8
commit cdcade404b
5 changed files with 353 additions and 0 deletions

10
docs/.vuepress/client.ts Normal file
View File

@ -0,0 +1,10 @@
import { type ClientConfig, defineClientConfig } from 'vuepress/client'
import HeroTintPlateConfig from './themes/components/HeroTintPlateConfig.vue'
import CanIUseConfig from './themes/components/CanIUseConfig.vue'
export default defineClientConfig({
enhance({ app }) {
app.component('HeroTintPlateConfig', HeroTintPlateConfig)
app.component('CanIUseConfig', CanIUseConfig)
},
}) as ClientConfig

View File

@ -0,0 +1,267 @@
<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { onClickOutside, useLocalStorage, useThrottleFn } from '@vueuse/core'
import { resolveCanIUse } from '../composables/caniuse.js'
import CodeViewer from './CodeViewer.vue'
interface Feature {
label: string
value: string
}
const api = 'https://api.caniuse.bitsofco.de/features'
const features = useLocalStorage('caniuse-features', [] as Feature[])
onMounted(async () => {
const res = await fetch(api)
const data = await res.json()
features.value = data?.map((item: any) => ({ label: item.title, value: item.id })) || []
})
const browserVersionList = ref([
{ label: '未来版本 (当前版本 + 3', value: 3, checked: false },
{ label: '未来版本 (当前版本 + 2', value: 2, checked: false },
{ label: '未来版本 (当前版本 + 1', value: 1, checked: false },
{ label: '当前版本', value: 0, disabled: true, checked: true },
{ label: '过去版本 (当前版本 - 1', value: -1, checked: false },
{ label: '过去版本 (当前版本 - 2', value: -2, checked: false },
{ label: '过去版本 (当前版本 - 3', value: -3, checked: false },
{ label: '过去版本 (当前版本 - 4', value: -4, checked: false },
{ label: '过去版本 (当前版本 - 5', value: -5, checked: false },
])
const input = ref('')
const isFocus = ref(false)
const searched = ref<Feature[]>()
const selected = ref<Feature | null>(null)
const embedType = ref('')
const browserVersion = computed(() => {
const values = browserVersionList.value.filter(item => item.checked).map(item => item.value)
if (values.length === 1 && values[0] === 0)
return ''
return values.join(',')
})
watch(() => [features.value, isFocus.value], () => {
if (!isFocus.value)
searched.value = features.value
}, { immediate: true })
const listEl = ref<HTMLUListElement | null>(null)
const inputEl = ref<HTMLInputElement | null>(null)
onClickOutside(listEl, () => {
isFocus.value = false
}, { ignore: [inputEl] })
const onInput = useThrottleFn(() => {
selected.value = null
if (!input.value) {
searched.value = features.value
}
else {
searched.value = features.value.filter(item => item.label.includes(input.value) || item.value.includes(input.value))
if (searched.value.length === 1)
selected.value = searched.value[0]
}
}, 300)
function onSelect(item: Feature) {
selected.value = item
input.value = item.label
isFocus.value = false
}
const output = computed(() => {
let content = '@[caniuse'
if (embedType.value)
content += ` ${embedType.value}`
if (browserVersion.value)
content += `{${browserVersion.value}}`
content += ']('
if (selected.value)
content += selected.value.value
return `${content})`
})
const rendered = ref('')
function render() {
if (!selected.value)
return
rendered.value = resolveCanIUse(selected.value.value, embedType.value, browserVersion.value)
}
</script>
<template>
<div class="caniuse-config-wrapper">
<form>
<div class="caniuse-form-item">
<label for="feature">选择特性</label>
<div class="feature-input">
<input
ref="inputEl" v-model="input" class="feature-input__input" type="text" name="feature"
placeholder="输入特性" @focus="isFocus = true" @input="onInput"
>
<span class="vpi-chevron-down" />
<ul v-show="isFocus" ref="listEl" class="feature-list">
<li v-for="item in searched" :key="item.value" @click="onSelect(item)">
{{ item.label }}
</li>
</ul>
</div>
</div>
<div class="caniuse-form-item">
<label for="embedType">嵌入方式</label>
<div class="caniuse-embed-type">
<label>
<input type="radio" name="embedType" value="" :checked="embedType === ''" @click="embedType = ''">
<span>iframe</span>
</label>
<label>
<input
type="radio" name="embedType" value="image" :checked="embedType === 'image'"
@click="embedType = 'image'"
> <span>image</span>
</label>
</div>
</div>
<div class="caniuse-form-item">
<label for="browserVersion">浏览器版本</label>
<div class="caniuse-browser-version">
<label v-for="item in browserVersionList" :key="item.value">
<input
v-model="item.checked" type="checkbox" name="browserVersion" :checked="item.checked"
:disabled="item.disabled"
>
<span>{{ item.label }}</span>
</label>
</div>
</div>
</form>
<div class="caniuse-output">
<h4>输出</h4>
<CodeViewer lang="md" :content="output" />
</div>
<div class="caniuse-render">
<button class="caniuse-render-button" type="button" :disabled="!selected" @click="render">
生成预览
</button>
</div>
<div v-html="rendered" />
</div>
</template>
<style scoped>
.caniuse-config-wrapper form {
padding: 20px;
border: solid 1px var(--vp-c-divider);
border-radius: 5px;
}
.caniuse-form-item {
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 16px;
}
.feature-input {
position: relative;
flex: 1;
margin-left: 10px;
}
.feature-input .vpi-chevron-down {
position: absolute;
top: 8px;
right: 10px;
width: 1em;
}
.feature-input__input {
width: 100%;
padding: 3px 40px 3px 16px;
border: solid 1px var(--vp-c-divider);
}
.feature-input__input:focus {
border-color: var(--vp-c-brand-1);
}
.feature-list {
position: absolute;
top: 100%;
left: 0;
z-index: 20;
width: 100%;
max-height: 420px;
padding: 10px 16px;
margin: 0;
overflow-y: auto;
list-style: none;
background: var(--vp-c-bg);
border: solid 1px var(--vp-c-divider);
border-top: none;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
box-shadow: var(--vp-shadow-2);
}
.feature-list li {
color: var(--vp-c-text-1);
cursor: pointer;
}
.feature-list li:hover {
color: var(--vp-c-brand-1);
}
.caniuse-embed-type {
margin-left: 10px;
}
.caniuse-embed-type label {
margin-right: 20px;
cursor: pointer;
}
.caniuse-browser-version {
display: flex;
flex: 1;
flex-wrap: wrap;
gap: 10px 30px;
margin-left: 10px;
}
.caniuse-render {
display: flex;
justify-content: flex-end;
padding-right: 20px;
padding-bottom: 20px;
}
.caniuse-render-button {
padding: 5px 20px;
font-weight: 500;
color: var(--vp-c-bg);
background-color: var(--vp-c-brand-1);
border-radius: 8px;
transition: background-color var(--t-color);
}
.caniuse-render-button:hover {
background-color: var(--vp-c-brand-2);
}
.caniuse-render-button[disabled] {
cursor: not-allowed;
background-color: var(--vp-c-brand-1);
opacity: 0.5;
}
</style>

View File

@ -0,0 +1,46 @@
export function resolveCanIUse(feature: string, mode: string, versions: string): string {
if (!feature)
return ''
if (mode === 'image') {
const link = 'https://caniuse.bitsofco.de/image/'
const alt = `Data on support for the ${feature} feature across the major browsers from caniuse.com`
return `<p><picture>
<source type="image/webp" srcset="${link}${feature}.webp">
<source type="image/png" srcset="${link}${feature}.png">
<img src="${link}${feature}.jpg" alt="${alt}" width="100%">
</picture></p>`
}
const periods = resolveVersions(versions)
const accessible = 'false'
const image = 'none'
const url = 'https://caniuse.bitsofco.de/embed/index.html'
const src = `${url}?feat=${feature}&periods=${periods}&accessible-colours=${accessible}&image-base=${image}`
return `<div class="ciu_embed" style="margin:16px 0" data-feature="${feature}"><iframe src="${src}" frameborder="0" width="100%" height="400px" title="Can I use ${feature}"></iframe></div>`
}
function resolveVersions(versions: string): string {
if (!versions)
return 'future_1,current,past_1,past_2'
const list = versions
.split(',')
.map(v => Number(v.trim()))
.filter(v => !Number.isNaN(v) && v >= -5 && v <= 3)
list.push(0)
const uniq = [...new Set(list)].sort((a, b) => b - a)
const result: string[] = []
uniq.forEach((v) => {
if (v < 0)
result.push(`past_${Math.abs(v)}`)
if (v === 0)
result.push('current')
if (v > 0)
result.push(`future_${v}`)
})
return result.join(',')
}

View File

@ -0,0 +1,15 @@
---
title: 主题工具包
author: pengzhanbo
createTime: 2024/04/16 16:27:03
permalink: /tools/
---
## 概述
主题工具包 旨在帮助用户在使用本主题提供的一些功能时,降低其使用门槛。
## 工具列表
- [caniuse 特性搜索](./caniuse.md)
- [首页背景色板配置](./home-hero-tint-plate.md)

View File

@ -0,0 +1,15 @@
---
title: caniuse 特性搜索
author: pengzhanbo
icon: fa-brands:css3
createTime: 2024/04/16 12:41:26
permalink: /tools/caniuse/
readingTime: false
editLink: false
contributors: false
lastUpdated: false
---
本工具用于帮助搜索 caniuse 中的特性。并生成 caniuse markdown 代码。
<CanIUseConfig />