Skip to content

Commit 32e1e3c

Browse files
committed
feat: polish Liquefy motion and import controls
1 parent 90d8f11 commit 32e1e3c

7 files changed

Lines changed: 277 additions & 13 deletions

File tree

src/components/shared/Pagination.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,20 @@ export function Pagination({
3636

3737
if (family === 'liquefy') {
3838
return (
39-
<LiquidPagination
40-
className={`liquefy-pagination liquefy-pagination--${size}`}
41-
count={totalPages}
42-
page={Math.min(totalPages, Math.max(1, current))}
43-
siblingCount={3}
44-
onPageChange={onPageChange}
45-
/>
39+
<div key={current} className="pagination-view-transition" data-pagination-page={current}>
40+
<LiquidPagination
41+
className={`liquefy-pagination liquefy-pagination--${size}`}
42+
count={totalPages}
43+
page={Math.min(totalPages, Math.max(1, current))}
44+
siblingCount={3}
45+
onPageChange={onPageChange}
46+
/>
47+
</div>
4648
);
4749
}
4850

4951
return (
50-
<ul className={`pagination pagination${size === 'sm' ? '-sm' : ''} justify-content-center mb-2`}>
52+
<ul key={current} data-pagination-page={current} className={`pagination pagination${size === 'sm' ? '-sm' : ''} justify-content-center mb-2`}>
5153
<li className={'page-item' + (current <= 1 ? ' disabled' : '')}>
5254
<a className="page-link" onClick={() => current > 1 && onPageChange(current - 1)}>
5355
&nbsp;&lt;&nbsp;

src/components/shell/AppShell.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,11 @@ export function AppShell() {
378378
className={'order-1 ms-0' + (accessLayout ? '' : ' ms-lg-3 me-lg-2')}
379379
style={{ marginTop: accessLayout ? '0' : isLiquefy ? '5.45rem' : '4.6rem', gridArea: 'main' }}
380380
>
381-
<div>
381+
<div
382+
key={location.key}
383+
className="route-view-transition"
384+
data-route-view={location.pathname}
385+
>
382386
<Outlet />
383387
</div>
384388
</main>

src/features/chuni/ChuniV2Pagination.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function ChuniV2Pagination({
6262
);
6363

6464
return (
65-
<div className="user-select-none d-inline-block" style={{ cursor: 'default' }}>
65+
<div key={normalizedCurrent} className="user-select-none d-inline-block pagination-view-transition" data-pagination-page={normalizedCurrent} style={{ cursor: 'default' }}>
6666
<ul className={listClassName}>
6767
<li className={`page-item${normalizedCurrent <= 1 ? ' disabled' : ''}`}>
6868
<a

src/features/mai2/Maimai2Pagination.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export function Maimai2Pagination({
5656
const pages = useMemo(() => pageEntries(current, totalPages), [current, totalPages]);
5757

5858
return (
59-
<ul className="pagination pagination-sm justify-content-center mb-2 user-select-none">
59+
<ul key={current} data-pagination-page={current} className="pagination pagination-sm justify-content-center mb-2 user-select-none">
6060
<li className={`page-item${current <= 1 ? ' disabled' : ''}`}>
6161
<a className="page-link" onClick={() => current > 1 && onPageChange(current - 1)}>
6262
&nbsp;&lt;&nbsp;

src/features/ongeki/OngekiPagination.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export function OngekiPagination({
8383
}, [current, normalizedCurrent, onPageChange]);
8484

8585
return (
86-
<div className="d-flex user-select-none" style={{ cursor: 'default' }}>
86+
<div key={normalizedCurrent} className="d-flex user-select-none pagination-view-transition" data-pagination-page={normalizedCurrent} style={{ cursor: 'default' }}>
8787
<ul className={`pagination pagination-sm justify-content-center ${marginClassName}`}>
8888
<li className={'page-item' + (normalizedCurrent <= 1 ? ' disabled' : '')}>
8989
<a

src/pages/ImporterPage.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ function ImportPanel({
8585
<p className="liquefy-import-panel__hint">{t('ImportPage.FileHint')}</p>
8686
</div>
8787
{input}
88-
<LiquidButton type="button" onClick={() => inputRef.current?.click()}>
88+
<LiquidButton
89+
className="liquefy-import-panel__button"
90+
type="button"
91+
onClick={() => inputRef.current?.click()}
92+
>
8993
{t('ImportPage.SelectFile')}
9094
</LiquidButton>
9195
</LiquidSurface>

src/styles/theme/liquefy.css

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,46 @@
520520
font-size: 0.9rem;
521521
}
522522

523+
[data-theme='liquefy'] .liquefy-import-panel__button {
524+
flex: 0 0 auto;
525+
min-width: 11rem;
526+
min-height: 3rem;
527+
padding: 0.7rem 1.25rem;
528+
border: 1px solid color-mix(in srgb, var(--lq-accent) 54%, var(--lq-glass-bright));
529+
border-radius: 999px;
530+
background: color-mix(in srgb, var(--lq-accent) 15%, var(--lq-glass-soft) 72%);
531+
box-shadow:
532+
0 10px 24px color-mix(in srgb, var(--lq-shadow-color) 48%, transparent),
533+
inset 0 1px 0 color-mix(in srgb, var(--lq-glass-bright) 92%, white),
534+
inset 0 -1px 0 var(--lq-glass-shade);
535+
color: var(--lq-foreground);
536+
white-space: nowrap;
537+
transition:
538+
background 180ms var(--lq-easing),
539+
border-color 180ms var(--lq-easing),
540+
box-shadow 180ms var(--lq-easing),
541+
transform 180ms var(--lq-easing);
542+
}
543+
544+
[data-theme='liquefy'] .liquefy-import-panel__button:hover:not(:disabled) {
545+
border-color: color-mix(in srgb, var(--lq-accent) 78%, white);
546+
background: color-mix(in srgb, var(--lq-accent) 26%, var(--lq-glass-soft) 68%);
547+
box-shadow:
548+
0 14px 30px color-mix(in srgb, var(--lq-shadow-color) 62%, transparent),
549+
inset 0 1px 0 var(--lq-glass-bright),
550+
inset 0 -1px 0 var(--lq-glass-shade);
551+
transform: translateY(-1px);
552+
}
553+
554+
[data-theme='liquefy'] .liquefy-import-panel__button:active:not(:disabled) {
555+
transform: translateY(0) scale(0.98);
556+
}
557+
558+
[data-theme='liquefy'] .liquefy-import-panel__button:focus-visible {
559+
outline: 2px solid var(--ui-focus-ring);
560+
outline-offset: 3px;
561+
}
562+
523563
[data-theme='liquefy'] .card-header,
524564
[data-theme='liquefy'] .card-footer {
525565
background: color-mix(in srgb, var(--lq-glass-soft) 74%, transparent);
@@ -1297,6 +1337,10 @@
12971337
padding: 1.1rem;
12981338
}
12991339

1340+
[data-theme='liquefy'] .liquefy-import-panel__button {
1341+
width: 100%;
1342+
}
1343+
13001344
[data-theme='liquefy'] [data-slot='dialog-content'],
13011345
[data-theme='liquefy'] .compat-modal,
13021346
[data-theme='liquefy'] .modal-dialog {
@@ -1324,3 +1368,213 @@
13241368
animation-iteration-count: 1 !important;
13251369
}
13261370
}
1371+
1372+
/* Low-amplitude motion for route, tab, pagination, and portal surfaces. */
1373+
[data-theme='liquefy'] .route-view-transition {
1374+
view-transition-name: page-content;
1375+
animation: liquefy-route-enter 220ms var(--lq-easing) both;
1376+
}
1377+
1378+
[data-theme='liquefy'] .pagination-view-transition,
1379+
[data-theme='liquefy'] [data-pagination-page] {
1380+
animation: liquefy-pagination-enter 180ms var(--lq-easing) both;
1381+
}
1382+
1383+
[data-theme='liquefy'] [data-slot='tabs-content'][data-state='active'],
1384+
[data-theme='liquefy'] .tab-pane.show.active {
1385+
animation: liquefy-tab-content-enter 190ms var(--lq-easing) both;
1386+
}
1387+
1388+
[data-theme='liquefy'] .tab-selector {
1389+
position: relative;
1390+
overflow: hidden;
1391+
transition:
1392+
color 180ms var(--lq-easing),
1393+
background-color 180ms var(--lq-easing),
1394+
border-color 180ms var(--lq-easing),
1395+
box-shadow 180ms var(--lq-easing),
1396+
transform 180ms var(--lq-easing);
1397+
}
1398+
1399+
[data-theme='liquefy'] .tab-selector::after {
1400+
position: absolute;
1401+
right: 0.55rem;
1402+
bottom: 0.15rem;
1403+
left: 0.55rem;
1404+
height: 2px;
1405+
border-radius: 999px;
1406+
content: '';
1407+
background: var(--ui-primary);
1408+
opacity: 0;
1409+
transform: scaleX(0);
1410+
transform-origin: center;
1411+
transition: transform 180ms var(--lq-easing), opacity 180ms var(--lq-easing);
1412+
}
1413+
1414+
[data-theme='liquefy'] .tab-selector-active::after {
1415+
opacity: 1;
1416+
transform: scaleX(1);
1417+
}
1418+
1419+
[data-theme='liquefy'] .tab-selector:active:not(:disabled) {
1420+
transform: translateY(1px) scale(0.985);
1421+
}
1422+
1423+
[data-theme='liquefy'] [data-slot='tabs-trigger']::after,
1424+
[data-theme='liquefy'] .nav-tabs .nav-link::after {
1425+
transform: scaleX(0);
1426+
transform-origin: center;
1427+
transition: transform 180ms var(--lq-easing), opacity 180ms var(--lq-easing);
1428+
}
1429+
1430+
[data-theme='liquefy'] [data-slot='tabs-trigger'][data-state='active']::after,
1431+
[data-theme='liquefy'] .nav-tabs .nav-link.active::after {
1432+
transform: scaleX(1);
1433+
opacity: 1;
1434+
}
1435+
1436+
[data-theme='liquefy'] .nav-tabs .nav-link {
1437+
position: relative;
1438+
transition: color 180ms var(--lq-easing), background-color 180ms var(--lq-easing), border-color 180ms var(--lq-easing);
1439+
}
1440+
1441+
[data-theme='liquefy'] .nav-tabs .nav-link::after {
1442+
position: absolute;
1443+
right: 0.55rem;
1444+
bottom: 0.15rem;
1445+
left: 0.55rem;
1446+
height: 2px;
1447+
content: '';
1448+
background: var(--lq-accent);
1449+
opacity: 0;
1450+
}
1451+
1452+
[data-theme='liquefy'] [data-slot='dialog-overlay'][data-dialog-state='open'],
1453+
[data-theme='liquefy'] [data-slot='sheet-overlay'][data-sheet-state='open'],
1454+
[data-theme='liquefy'] .modal-backdrop.show,
1455+
[data-theme='liquefy'] .offcanvas-backdrop.show {
1456+
animation: liquefy-overlay-enter 180ms ease-out both;
1457+
}
1458+
1459+
[data-theme='liquefy'] [data-slot='dialog-content'][data-dialog-state='open'],
1460+
[data-theme='liquefy'] [data-slot='sheet-content'][data-sheet-state='open'],
1461+
[data-theme='liquefy'] .modal.show .modal-dialog,
1462+
[data-theme='liquefy'] .offcanvas.show {
1463+
animation: liquefy-surface-enter 220ms var(--lq-easing) both;
1464+
}
1465+
1466+
[data-theme='liquefy'] .lq-dialog__backdrop,
1467+
[data-theme='liquefy'] .lq-drawer__backdrop {
1468+
animation: liquefy-overlay-enter 180ms ease-out both;
1469+
}
1470+
1471+
[data-theme='liquefy'] .lq-dialog[data-open] {
1472+
animation: liquefy-surface-enter 220ms var(--lq-easing) both;
1473+
}
1474+
1475+
[data-theme='liquefy'] [data-slot='dialog-close'],
1476+
[data-theme='liquefy'] .btn-close,
1477+
[data-theme='liquefy'] .lq-dialog__header > .lq-button,
1478+
[data-theme='liquefy'] .lq-drawer__close {
1479+
box-sizing: border-box;
1480+
display: inline-grid;
1481+
width: 2.25rem !important;
1482+
min-width: 2.25rem !important;
1483+
height: 2.25rem !important;
1484+
min-height: 2.25rem !important;
1485+
place-items: center;
1486+
padding: 0 !important;
1487+
border: 1px solid color-mix(in srgb, var(--lq-glass-bright) 72%, var(--lq-accent));
1488+
border-radius: 999px !important;
1489+
background-color: color-mix(in srgb, var(--lq-glass-soft) 74%, transparent) !important;
1490+
box-shadow: inset 0 1px 0 var(--lq-glass-bright), 0 5px 16px color-mix(in srgb, var(--lq-shadow-color) 48%, transparent);
1491+
color: var(--lq-foreground);
1492+
opacity: 1;
1493+
transition: background-color 160ms var(--lq-easing), border-color 160ms var(--lq-easing), box-shadow 160ms var(--lq-easing), transform 160ms var(--lq-easing);
1494+
}
1495+
1496+
[data-theme='liquefy'] .lq-dialog__header > .lq-button {
1497+
aspect-ratio: 1;
1498+
flex: 0 0 2.25rem;
1499+
font-size: 1.35rem;
1500+
line-height: 1;
1501+
text-decoration: none;
1502+
}
1503+
1504+
[data-theme='liquefy'] .lq-dialog__header > .lq-button .lq-button__content {
1505+
color: var(--lq-foreground);
1506+
display: grid;
1507+
min-height: 100%;
1508+
place-items: center;
1509+
width: 100%;
1510+
}
1511+
1512+
[data-theme='liquefy'] .lq-dialog__header > .lq-button .lq-button__content > span {
1513+
display: block;
1514+
font-size: 1.35rem;
1515+
font-weight: 400;
1516+
line-height: 1;
1517+
}
1518+
1519+
[data-theme='liquefy'] [data-slot='dialog-close']:hover,
1520+
[data-theme='liquefy'] .btn-close:hover,
1521+
[data-theme='liquefy'] .lq-dialog__header > .lq-button:hover,
1522+
[data-theme='liquefy'] .lq-drawer__close:hover {
1523+
background-color: color-mix(in srgb, var(--lq-accent) 18%, var(--lq-glass-soft)) !important;
1524+
border-color: color-mix(in srgb, var(--lq-accent) 60%, var(--lq-glass-bright));
1525+
box-shadow: inset 0 1px 0 var(--lq-glass-bright), 0 8px 20px color-mix(in srgb, var(--lq-shadow-color) 58%, transparent);
1526+
transform: translateY(-1px);
1527+
}
1528+
1529+
[data-theme='liquefy'] [data-slot='dialog-close']:focus-visible,
1530+
[data-theme='liquefy'] .btn-close:focus-visible,
1531+
[data-theme='liquefy'] .lq-dialog__header > .lq-button:focus-visible,
1532+
[data-theme='liquefy'] .lq-drawer__close:focus-visible {
1533+
outline: 2px solid var(--ui-focus-ring);
1534+
outline-offset: 3px;
1535+
}
1536+
1537+
@keyframes liquefy-route-enter {
1538+
from { transform: translateY(6px); }
1539+
to { transform: translateY(0); }
1540+
}
1541+
1542+
@keyframes liquefy-tab-content-enter {
1543+
from { transform: translateY(4px); }
1544+
to { transform: translateY(0); }
1545+
}
1546+
1547+
@keyframes liquefy-pagination-enter {
1548+
from { transform: translateY(3px) scale(0.99); }
1549+
to { transform: translateY(0) scale(1); }
1550+
}
1551+
1552+
@keyframes liquefy-overlay-enter {
1553+
from { opacity: 0; }
1554+
to { opacity: 1; }
1555+
}
1556+
1557+
@keyframes liquefy-surface-enter {
1558+
from { opacity: 0; transform: translateY(7px) scale(0.985); }
1559+
to { opacity: 1; transform: translateY(0) scale(1); }
1560+
}
1561+
1562+
@media (prefers-reduced-motion: reduce) {
1563+
[data-theme='liquefy'] .route-view-transition,
1564+
[data-theme='liquefy'] .pagination-view-transition,
1565+
[data-theme='liquefy'] [data-pagination-page],
1566+
[data-theme='liquefy'] [data-slot='tabs-content'][data-state='active'],
1567+
[data-theme='liquefy'] .tab-pane.show.active,
1568+
[data-theme='liquefy'] [data-slot='dialog-overlay'][data-dialog-state='open'],
1569+
[data-theme='liquefy'] [data-slot='sheet-overlay'][data-sheet-state='open'],
1570+
[data-theme='liquefy'] [data-slot='dialog-content'][data-dialog-state='open'],
1571+
[data-theme='liquefy'] [data-slot='sheet-content'][data-sheet-state='open'],
1572+
[data-theme='liquefy'] .modal.show .modal-dialog,
1573+
[data-theme='liquefy'] .offcanvas.show,
1574+
[data-theme='liquefy'] .lq-dialog__backdrop,
1575+
[data-theme='liquefy'] .lq-drawer__backdrop,
1576+
[data-theme='liquefy'] .lq-dialog[data-open] {
1577+
animation: none !important;
1578+
transition: none !important;
1579+
}
1580+
}

0 commit comments

Comments
 (0)