mirror of
https://github.com/jason5ng32/MyIP.git
synced 2026-11-04 08:55:47 +00:00
refactor(ui): new InputGroup primitive + QueryIP switches to it
InputGroup owns border / rounded / shadow / focus-within:ring at the wrapper level; inside, the [&>input] / [&>button] permeating selectors flatten child elements' independent border / shadow / ring / rounded. No more hand-written rounded-r-none / rounded-l-none / -ml-px border- collapse hacks. QueryIP is the first beneficiary; 5 more Input+Button stitching sites in advanced-tools/ (DnsResolver / CensorshipCheck / Whois / GlobalLatencyTest) will migrate later together. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
9f5c80172d
commit
590a4aa5e3
3 files changed
+42
-5
No files matched your search
@@ -0,0 +1,36 @@
|
||||
<script setup>
|
||||
// shadcn-vue Input Group:把 Input + Button(或 Input + addon)拼成一个
|
||||
// 视觉一体的输入条。wrapper 自己承担 border / rounded / shadow / focus-ring,
|
||||
// 用 [&>*] 透穿选择器把内部 <input> / <button> 的独立边框/阴影/ring 扁平化。
|
||||
//
|
||||
// 用法:
|
||||
// <InputGroup>
|
||||
// <Input v-model="q" placeholder="..." />
|
||||
// <Button :disabled="..." @click="...">Go</Button>
|
||||
// </InputGroup>
|
||||
//
|
||||
// 需要分隔线时:<InputGroup class="[&>*:not(:first-child)]:border-l [&>*:not(:first-child)]:border-input" />
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
defineProps({
|
||||
class: { type: [String, Array, Object], default: undefined },
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="cn(
|
||||
'flex items-stretch w-full rounded-md border border-input bg-background shadow-sm overflow-hidden transition-colors',
|
||||
'focus-within:ring-1 focus-within:ring-ring',
|
||||
// 扁平化所有 input / button 子元素:取消它们各自的 border / shadow / ring / rounded,
|
||||
// 让整个 group 看起来是一个整体
|
||||
'[&>input]:border-0 [&>input]:shadow-none [&>input]:rounded-none [&>input]:bg-transparent',
|
||||
'[&>input]:focus-visible:ring-0 [&>input]:focus-visible:outline-none',
|
||||
'[&>button]:border-0 [&>button]:shadow-none [&>button]:rounded-none',
|
||||
'[&>button]:focus-visible:ring-0 [&>button]:focus-visible:outline-none',
|
||||
$props.class,
|
||||
)"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1 @@
|
||||
export { default as InputGroup } from './InputGroup.vue';
|
||||
@@ -15,19 +15,18 @@
|
||||
<DialogHeader :icon="Search" :title="t('ipcheck.Title')" />
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- 输入 + 查询按钮(border-collapse 拼接) -->
|
||||
<div class="flex">
|
||||
<!-- Input Group:整条输入条由 group 承担 border / rounded / focus-ring,
|
||||
内部 Input / Button 的独立样式被 group 扁平化,不再需要 rounded-r-none / -ml-px 拼接 -->
|
||||
<InputGroup>
|
||||
<Input type="text" id="inputIP" name="inputIP"
|
||||
class="rounded-r-none"
|
||||
:placeholder="t('ipcheck.Placeholder')"
|
||||
v-model="inputIP" @keyup.enter="submitQuery" />
|
||||
<Button id="sumitQueryButton" type="button"
|
||||
class="rounded-l-none -ml-px shrink-0"
|
||||
:disabled="!isValidIP(inputIP) || isChecking === 'running'"
|
||||
@click="submitQuery">
|
||||
{{ t('ipcheck.Button') }}
|
||||
</Button>
|
||||
</div>
|
||||
</InputGroup>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<p v-if="modalQueryError" class="text-sm text-destructive">{{ modalQueryError }}</p>
|
||||
@@ -179,6 +178,7 @@ import { Dialog, DialogContent, DialogHeader } from '@/components/ui/dialog';
|
||||
import { JnTooltip } from '@/components/ui/tooltip';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { InputGroup } from '@/components/ui/input-group';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import {
|
||||
|
||||
Reference in new issue
Block a user