Full 1:1 migration preserving all visuals, animations and behavior: - Nuxt 4 + Vue 3 (script setup, TypeScript strict) with SSG output - Tailwind CSS v4 with @tailwindcss/vite - Ant Design Vue 4 (dark theme, RTL, Persian locale) for design system - Pinia for state management (ui + contact stores) - motion-v (framer-motion port) for all animations - lucide-vue-next for icons - SEO improvements: og:image, canonical fix, real 404 page, JSON-LD services - JS bundle reduced from 302KB to 239KB gzip - Docker/nginx deployment preserved (out/ -> nginx) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
119 lines
3.4 KiB
CSS
119 lines
3.4 KiB
CSS
/*
|
|
* Ant Design Vue ↔ project look.
|
|
* antd's CSS-in-JS is unlayered while Tailwind v4 lives in cascade layers, so Tailwind classes
|
|
* can't restyle antd elements. These unlayered rules pin antd form controls to the exact
|
|
* pre-migration styling (same values as the old Tailwind `inputCls` / submit button).
|
|
*/
|
|
|
|
/* ---- form shell ---- */
|
|
.contact-form.ant-form {
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
line-height: inherit;
|
|
}
|
|
/* antd resets items and their grid wrappers to 14px/1.5714; inherit like the original markup did
|
|
(the control line box decides the gap under the inline-block textarea) */
|
|
.contact-form .ant-form-item,
|
|
.contact-form .ant-form-item .ant-row,
|
|
.contact-form .ant-form-item .ant-col {
|
|
margin-bottom: 0;
|
|
font-size: inherit;
|
|
line-height: inherit;
|
|
}
|
|
.contact-form .ant-form-item .ant-form-item-label {
|
|
padding: 0 0 8px; /* mb-2 */
|
|
line-height: 16px;
|
|
}
|
|
.contact-form .ant-form-item-label > label {
|
|
width: 100%; /* original labels were full-width blocks */
|
|
height: auto;
|
|
font-size: 12px; /* text-xs */
|
|
line-height: 16px;
|
|
color: var(--color-muted);
|
|
}
|
|
.contact-form .ant-form-item-explain {
|
|
font-size: 12px;
|
|
line-height: 20px;
|
|
padding-top: 4px;
|
|
}
|
|
|
|
/* ---- inputs (= w-full rounded-lg border border-line bg-bg px-4 py-3.5 text-sm text-ink) ---- */
|
|
.contact-form .ant-input {
|
|
width: 100%;
|
|
border-radius: 8px;
|
|
border: 1px solid var(--color-line);
|
|
background-color: var(--color-bg);
|
|
padding: 14px 16px;
|
|
font-family: inherit;
|
|
font-size: 14px;
|
|
line-height: 20px;
|
|
color: var(--color-ink);
|
|
box-shadow: none;
|
|
transition-property: color, background-color, border-color;
|
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
transition-duration: 150ms;
|
|
}
|
|
.contact-form .ant-input::placeholder {
|
|
color: color-mix(in oklab, var(--color-muted) 50%, transparent);
|
|
}
|
|
.contact-form .ant-input:hover {
|
|
border-color: var(--color-line);
|
|
}
|
|
.contact-form .ant-input:focus,
|
|
.contact-form .ant-input-focused {
|
|
border-color: var(--color-accent);
|
|
outline: none;
|
|
box-shadow: none;
|
|
}
|
|
/* antd's .ant-input-rtl forces direction:rtl; honour an explicit dir="ltr" (phone field) */
|
|
.contact-form .ant-input[dir="ltr"] {
|
|
direction: ltr;
|
|
text-align: left;
|
|
}
|
|
.contact-form textarea.ant-input {
|
|
resize: none;
|
|
min-height: 0;
|
|
vertical-align: baseline; /* native inline-block textarea alignment (antd sets bottom) */
|
|
}
|
|
|
|
/* ---- submit (= rounded-full bg-accent py-4 font-bold text-bg, hover:bg-accent-soft + glow) ---- */
|
|
.contact-form .ant-btn.contact-submit {
|
|
display: flex;
|
|
width: 100%;
|
|
height: auto;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
border: 0;
|
|
border-radius: calc(infinity * 1px); /* = tailwind rounded-full */
|
|
background-color: var(--color-accent);
|
|
padding: 16px 0;
|
|
font-family: inherit;
|
|
font-size: 16px;
|
|
line-height: 24px;
|
|
font-weight: 700;
|
|
color: var(--color-bg);
|
|
box-shadow: none;
|
|
cursor: default;
|
|
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
.contact-form .ant-btn.contact-submit > span {
|
|
display: inline;
|
|
}
|
|
@media (hover: hover) {
|
|
.contact-form .ant-btn.contact-submit:hover {
|
|
background-color: var(--color-accent-soft);
|
|
color: var(--color-bg);
|
|
box-shadow: 0 8px 45px rgba(255, 90, 0, 0.45);
|
|
}
|
|
}
|
|
.contact-form .ant-btn.contact-submit:disabled {
|
|
opacity: 0.6;
|
|
border: 0;
|
|
}
|
|
/* no click-wave ring (wasn't part of the original button) */
|
|
.contact-form .ant-btn.contact-submit::after,
|
|
.contact-form .ant-wave {
|
|
display: none;
|
|
}
|