Подпись StackWorks: вариант «штамп» со знаком и анимацией полос
Claude-Session: https://claude.ai/code/session_01BFaqS6mH9sa99RWghq2j46
Этот коммит содержится в:
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Подпись студии StackWorks («штамп»): знак и две строки - «разработка и поддержка» / StackWorks.
|
||||||
|
* В остальных проектах она ставится скриптом https://stackworks.ru/sign/sw-sign.js,
|
||||||
|
* здесь - компонентом, чтобы React не спорил с чужими изменениями страницы.
|
||||||
|
* Оформление в src/index.css, классы swsig*.
|
||||||
|
*/
|
||||||
|
export default function SwSignature({ dark = false }: { dark?: boolean }) {
|
||||||
|
const bg = dark ? '#F3F1EB' : '#16171C';
|
||||||
|
const fg = dark ? '#16171C' : '#F3F1EB';
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
className={'swsig' + (dark ? ' swsig-dark' : '')}
|
||||||
|
href="https://stackworks.ru/?utm_source=mail.stackworks.ru&utm_medium=signature"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
aria-label="Разработка и поддержка - StackWorks"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||||
|
<rect x="2" y="2" width="96" height="96" rx="25" fill={bg} />
|
||||||
|
<rect className="b b1" x="20" y="29" width="44" height="12" rx="6" fill={fg} />
|
||||||
|
<rect className="b b2" x="30" y="45" width="50" height="12" rx="6" fill="#FF4A1C" />
|
||||||
|
<rect className="b b3" x="40" y="61" width="34" height="12" rx="6" fill={fg} />
|
||||||
|
</svg>
|
||||||
|
<span className="swsig-txt">
|
||||||
|
<span className="swsig-cap">разработка и поддержка</span>
|
||||||
|
<span className="swsig-word">Stack<i>Works</i></span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import SwSignature from '@/components/common/SwSignature';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import * as LucideIcons from 'lucide-react';
|
import * as LucideIcons from 'lucide-react';
|
||||||
@@ -365,6 +366,10 @@ export function Sidebar() {
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-center px-3 py-3">
|
||||||
|
<SwSignature dark />
|
||||||
|
</div>
|
||||||
|
|
||||||
{layouts.length > 1 && (
|
{layouts.length > 1 && (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<div className="sw-aside-foot flex items-center justify-around border-t bg-background px-2 py-2">
|
<div className="sw-aside-foot flex items-center justify-around border-t bg-background px-2 py-2">
|
||||||
|
|||||||
@@ -165,3 +165,20 @@ aside.sw-aside .text-muted-foreground { color: #8d8f96 !important; }
|
|||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
main h1 { font-size: 1.6rem; }
|
main h1 { font-size: 1.6rem; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* подпись студии (компонент SwSignature, повторяет https://stackworks.ru/sign/sw-sign.js) */
|
||||||
|
.swsig { --ink: #16171c; --cap: #6a6c75; --acc: #ff4a1c; display: inline-flex; align-items: center; gap: 10px;
|
||||||
|
min-height: 44px; text-decoration: none; color: var(--ink); border-radius: 8px; }
|
||||||
|
.swsig-dark { --ink: #f3f1eb; --cap: #9a9ca3; }
|
||||||
|
.swsig svg { width: 30px; height: 30px; flex: 0 0 auto; display: block; }
|
||||||
|
.swsig-txt { display: flex; flex-direction: column; gap: 4px; }
|
||||||
|
.swsig-cap { font: 400 11.5px/1 'SW Inter', system-ui, sans-serif; color: var(--cap); white-space: nowrap; }
|
||||||
|
.swsig-word { font: 700 16px/1 'SW Rubik', sans-serif; letter-spacing: -.01em; color: var(--ink); white-space: nowrap; }
|
||||||
|
.swsig-word i { font-style: normal; color: var(--acc); }
|
||||||
|
@keyframes swsig-shuffle { 0%, 100% { transform: translateX(0); } 45% { transform: translateX(9px); } }
|
||||||
|
.swsig .b { transform-box: fill-box; }
|
||||||
|
.swsig:hover .b, .swsig:focus-visible .b { animation: swsig-shuffle .38s ease-in-out both; }
|
||||||
|
.swsig:hover .b2, .swsig:focus-visible .b2 { animation-delay: .07s; }
|
||||||
|
.swsig:hover .b3, .swsig:focus-visible .b3 { animation-delay: .14s; }
|
||||||
|
.swsig:focus-visible { outline: 2px solid var(--acc); outline-offset: 4px; }
|
||||||
|
@media (prefers-reduced-motion: reduce) { .swsig .b { animation: none !important; } }
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { ArrowRight, Loader2 } from 'lucide-react';
|
import { ArrowRight, Loader2 } from 'lucide-react';
|
||||||
|
|
||||||
import Logo from '@/components/common/Logo';
|
import Logo from '@/components/common/Logo';
|
||||||
|
import SwSignature from '@/components/common/SwSignature';
|
||||||
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
|
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
@@ -43,7 +44,7 @@ export default function LoginPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen items-center justify-center bg-content-background px-4">
|
<div className="flex min-h-screen flex-col items-center justify-center gap-6 bg-content-background px-4">
|
||||||
<Card className="w-full max-w-sm shadow-sm">
|
<Card className="w-full max-w-sm shadow-sm">
|
||||||
<CardHeader className="items-center text-center">
|
<CardHeader className="items-center text-center">
|
||||||
<Logo />
|
<Logo />
|
||||||
@@ -87,6 +88,7 @@ export default function LoginPage() {
|
|||||||
</form>
|
</form>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
<SwSignature />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user