refactor: use grid for proxy list layout

This commit is contained in:
Haishan 2020-06-15 23:17:50 +08:00
parent 98f0753cdc
commit 0bf2d72d05
6 changed files with 87 additions and 65 deletions

View file

@ -97,6 +97,9 @@ body {
Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji,
Segoe UI Symbol, 'PingFang SC', 'Microsoft YaHei', '微软雅黑', Arial,
sans-serif;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
margin: 0;
padding: 0;
}

View file

@ -4,6 +4,10 @@
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: space-between;
max-width: 280px;
@media (--breakpoint-not-small) {
min-width: 200px;
@ -19,6 +23,13 @@
&.error {
opacity: 0.5;
}
&.selectable {
transition: transform 0.2s ease-in-out;
cursor: pointer;
&:hover {
transform: translateY(-2px);
}
}
}
.proxyType {
@ -37,20 +48,28 @@
.proxyName {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 5px;
font-size: 0.85em;
@media (--breakpoint-not-small) {
font-size: 1.1em;
font-size: 1em;
}
}
.proxySmall {
.now {
outline: pink solid 1px;
width: 13px;
height: 13px;
border-radius: 50%;
border: 1px solid var(--color-background);
&.now {
border-color: var(--color-text-secondary);
}
&.selectable {
transition: transform 0.1s ease-in-out;
cursor: pointer;
&:hover {
transform: scale(1.2);
}
}
width: 12px;
height: 12px;
border-radius: 8px;
}

View file

@ -41,9 +41,17 @@ type ProxyProps = {
now?: boolean;
proxy: any;
latency: any;
isSelectable?: boolean;
onClick?: (proxyName: string) => unknown;
};
function ProxySmallImpl({ now, name, latency }: ProxyProps) {
function ProxySmallImpl({
now,
name,
latency,
isSelectable,
onClick,
}: ProxyProps) {
const color = useMemo(() => getLabelColor(latency), [latency]);
const title = useMemo(() => {
let ret = name;
@ -55,20 +63,37 @@ function ProxySmallImpl({ now, name, latency }: ProxyProps) {
return (
<div
title={title}
className={cx(s0.proxySmall, { [s0.now]: now })}
className={cx(s0.proxySmall, {
[s0.now]: now,
[s0.selectable]: isSelectable,
})}
style={{ backgroundColor: color }}
onClick={() => {
isSelectable && onClick && onClick(name);
}}
/>
);
}
function ProxyImpl({ now, name, proxy, latency }: ProxyProps) {
function ProxyImpl({
now,
name,
proxy,
latency,
isSelectable,
onClick,
}: ProxyProps) {
const color = useMemo(() => getLabelColor(latency), [latency]);
return (
<div
className={cx(s0.proxy, {
[s0.now]: now,
[s0.error]: latency && latency.error,
[s0.selectable]: isSelectable,
})}
onClick={() => {
isSelectable && onClick && onClick(name);
}}
>
<div className={s0.proxyName}>{name}</div>
<div className={s0.row}>

View file

@ -16,7 +16,7 @@ import { ProxyList, ProxyListSummaryView } from './ProxyList';
import s0 from './ProxyGroup.module.css';
const { useCallback, useMemo, useState } = React;
const { createElement, useCallback, useMemo, useState } = React;
function ZapWrapper() {
return (
@ -73,16 +73,12 @@ function ProxyGroupImpl({ name, all, type, now, isOpen, apiConfig, dispatch }) {
<ZapWrapper />
</Button>
</div>
{isOpen ? (
<ProxyList
all={all}
now={now}
isSelectable={isSelectable}
itemOnTapCallback={itemOnTapCallback}
/>
) : (
<ProxyListSummaryView all={all} />
)}
{createElement(isOpen ? ProxyList : ProxyListSummaryView, {
all,
now,
isSelectable,
itemOnTapCallback,
})}
</div>
);
}

View file

@ -1,22 +1,13 @@
.list {
display: flex;
flex-wrap: wrap;
margin-top: 8px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(auto, 280px));
grid-gap: 10px;
}
.proxy {
margin-right: 5px;
margin-bottom: 5px;
@media (--breakpoint-not-small) {
margin-right: 10px;
margin-bottom: 10px;
}
transition: transform 0.2s ease-in-out;
&.proxySelectable {
cursor: pointer;
&:hover {
transform: translateY(-2px);
}
}
.listSummaryView {
margin-top: 8px;
display: grid;
grid-template-columns: repeat(auto-fill, 13px);
grid-gap: 10px;
}

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import cx from 'clsx';
/* import cx from 'clsx'; */
import { Proxy, ProxySmall } from './Proxy';
@ -25,20 +25,14 @@ export function ProxyList({
return (
<div className={s.list}>
{proxies.map((proxyName) => {
const proxyClassName = cx(s.proxy, {
[s.proxySelectable]: isSelectable,
});
return (
<div
className={proxyClassName}
<Proxy
key={proxyName}
onClick={() => {
if (!isSelectable || !itemOnTapCallback) return;
itemOnTapCallback(proxyName);
}}
>
<Proxy name={proxyName} now={proxyName === now} />
</div>
onClick={itemOnTapCallback}
isSelectable={isSelectable}
name={proxyName}
now={proxyName === now}
/>
);
})}
</div>
@ -52,22 +46,16 @@ export function ProxyListSummaryView({
itemOnTapCallback,
}: ProxyListProps) {
return (
<div className={s.list}>
<div className={s.listSummaryView}>
{all.map((proxyName) => {
const proxyClassName = cx(s.proxy, {
[s.proxySelectable]: isSelectable,
});
return (
<div
className={proxyClassName}
<ProxySmall
key={proxyName}
onClick={() => {
if (!isSelectable || !itemOnTapCallback) return;
itemOnTapCallback(proxyName);
}}
>
<ProxySmall name={proxyName} now={proxyName === now} />
</div>
onClick={itemOnTapCallback}
isSelectable={isSelectable}
name={proxyName}
now={proxyName === now}
/>
);
})}
</div>