contacts-pane
Version:
Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.
620 lines (524 loc) • 17.1 kB
CSS
/* Focus indicator for keyboard navigation */
.contactPane table tr[tabindex="0"]:focus {
outline: var(--focus-ring-width) solid var(--color-primary);
outline-offset: 2px;
background: var(--color-info-bg);
}
/* contactsPane styles — extracted from inline styles in contactsPane.js */
/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */
/* ── Layout: Three-column browser ────────────────────────────── */
.contactPane .peopleSection .selected {
background-color: var(--color-info-bg) ;
}
.contactPane .detailSection,
.contactPane .addressBookSection {
display: flex;
flex-direction: column;
align-items: stretch;
flex: 1 1 0; /* allow it to grow but not force wrap */
min-width: 0; /* allow sections to collapse when stacked */
box-sizing: border-box;
background: var(--color-section-bg);
}
.contactPane .detailsSectionContent {
flex: 1 1 auto;
min-height: 12.5rem; /* 200px */
padding: var(--spacing-lg);
max-width: 56.25rem; /* 900px */
width: 100%;
box-sizing: border-box;
}
.contactPane .detailsSectionContent--wide {
max-width: 56.25rem; /* 900px */
}
.contactPane .cardFooter {
display: flex;
flex-wrap: nowrap; /* keep buttons inline */
align-items: center; /* vertical centering if varied heights */
gap: var(--spacing-xs);
padding-top: var(--spacing-md);
margin-top: var(--spacing-md);
}
.contactPane .detailsSectionContent {
margin: 0;
}
/* ── Contact type chooser ───────────────────────────────────── */
.contactPane .contactTypeChooser {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
max-width: 22.5rem; /* 360px */
}
.contactPane .contactTypeChooser h3 {
margin: 0 0 var(--spacing-xs) 0;
font-size: var(--font-size-lg);
}
.contactPane .contactTypeSelect {
height: var(--min-touch-target);
border: var(--border-width-sm, 1px) solid var(--color-border-pale);
border-radius: var(--border-radius-base);
padding: 0 var(--spacing-sm);
font-size: var(--font-size-sm);
background: var(--color-section-bg);
}
/* ── Search ──────────────────────────────────────────────────── */
.contactPane .allGroupsButton {
border-radius: var(--border-radius-full) ;
/* existing styles */
}
/* wrapper to position clear icon/button */
.contactPane .searchDiv {
position: relative;
}
.contactPane .searchInput {
height: var(--min-touch-target);
border: var(--border-width-sm, 1px) solid var(--color-border-pale);
background-color: var(--color-section-bg);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23999' viewBox='0 0 24 24' width='20' height='20'%3E%3Cpath d='M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99c.41.41 1.09.41 1.5 0s.41-1.09 0-1.5l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 0.5rem center; /* 8px */
background-size: 1.25rem 1.25rem; /* 20px 20px */
border-radius: var(--border-radius-base);
padding: 0 var(--spacing-sm) 0 2.125rem; /* 34px */
font-size: var(--font-size-base);
width: 100%;
box-sizing: border-box;
}
/* clear button inside search input */
.contactPane .searchClearButton {
position: absolute;
right: var(--spacing-sm);
top: 50%;
transform: translateY(-50%);
border: none;
background: transparent;
font-size: var(--font-size-base);
line-height: 1;
padding: 0;
cursor: pointer;
color: var(--color-text-muted);
/* visibility is controlled via the generic `.hidden` utility class */
display: block;
}
.contactPane .searchClearButton.hidden {
display: none;
}
.contactPane .searchClearButton:hover {
color: var(--color-text);
}
/* ── Contact toolbar (top-right link + delete) ──────────────── */
.contactPane .contact-toolbar {
display: flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-xs) 0;
}
.contactPane .contact-toolbar a {
margin: 0.3rem;
}
.contactPane .contact-toolbar a img {
width: 1.3rem;
height: 1rem;
margin: 0;
}
.contact-toolbar .deleteButton {
margin-left: auto; /* keeps delete icon on the right */
margin-right: var(--spacing-xxxs, 0.2rem);
width: var(--icon-xxs, 1rem);
height: var(--icon-xxs, 1rem);
float: none; /* important: prevents overlap behavior */
}
/* ── "All" groups button ─────────────────────────────────────── */
.contactPane .allGroupsButton {
margin-left: var(--spacing-md);
font-size: var(--font-size-base);
}
.contactPane .allGroupsButton--loading {
background-color: var(--color-primary);
}
.contactPane .allGroupsButton--active {
background-color: var(--color-primary);
color: var(--color-background);
}
.contactPane .allGroupsButton--loaded {
background-color: var(--color-primary);
}
/* ── Mint new address book ───────────────────────────────────── */
.contactPane .claimSuccess {
font-size: var(--font-size-xl);
}
.contactPane {
display: flex;
flex-direction: column;
min-height: 0;
}
.contactPane .addressBook-grid {
display: flex;
flex-wrap: nowrap; /* keep sections side-by-side */
flex: 1;
min-width: 0; /* allow it to shrink */
align-items: stretch;
width: 100%;
box-sizing: border-box;
overflow-x: hidden;
}
@media ((min-width: 500px) and (max-width: 900px)) {
.contactPane .addressBookSection {
max-width: 900px;
}
.contactPane .addressBookSection section {
max-width: 485px;
}
}
.contactPane.contactPane--narrow .addressBook-grid {
flex-direction: column ;
flex-wrap: nowrap ;
min-width: 0 ;
overflow-x: hidden ;
}
.contactPane.contactPane--narrow .addressBookSection,
.contactPane.contactPane--narrow .detailSection {
flex: 1 1 100% ;
max-width: 100% ;
min-width: 0 ;
width: 100% ;
}
@media (max-width: 1000px) {
/* Stack sidebar + details vertically on narrow screens */
.contactPane {
min-height: auto ;
}
.contactPane .addressBook-grid {
flex-direction: column ;
flex-wrap: nowrap ;
min-height: auto ;
height: auto ;
}
.contactPane .addressBookSection,
.contactPane .detailSection {
order: initial ;
flex: none ;
width: 100% ;
max-width: 100% ;
min-width: 0 ;
}
.contactPane .addressBookSection {
max-height: none ;
min-height: auto ;
overflow-y: visible ;
padding-bottom: var(--spacing-lg) ;
display: flex ;
flex-direction: column ;
height: auto ;
}
.contactPane .peopleSection ul {
max-height: 50vh;
overflow-y: auto;
}
.contactPane .detailSection {
max-height: none ;
min-height: auto ;
overflow-y: visible ;
}
.contactPane .detailsSectionContent {
display: flex ;
flex-direction: column ;
justify-content: flex-start ;
align-items: stretch ;
min-height: auto ;
height: auto ;
overflow-y: visible ;
}
.contactPane .detailSection > .detailsSectionContent {
padding-top: var(--spacing-sm) ;
box-sizing: border-box ;
}
/* Keep a normal mobile text scale while preserving comfortable touch targets */
/* The following rule made all text much larger on mobile; comment out to restore normal font size for non-buttons.
.contactPane,
.contactPane * {
font-size: 1.5rem !important;
} */
.contactPane .actionButton,
.contactPane .searchInput,
.contactPane .flatButton,
.contactPane .buttonSection button,
.contactPane .groupButtonsList button {
min-height: calc(var(--min-touch-target) + 0.5em) ;
font-size: 1.5rem ;
padding: 0.875em 1em ;
}
.contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide, .contactPane .group-membership-item .group-membership-toolbar > [data-testid="deleteButtonWithCheck"],
.individualPane .hoverControl img.hoverControlHide,
.individualPane .hoverControl [data-testid="deleteButtonWithCheck"] {
display: inline-flex ;
visibility: visible ;
opacity: 1 ;
}
}
/* Card Section Background */
.contactPane .addressBookSection.section-bg {
background: var(--color-section-bg);
padding: var(--spacing-md);
box-sizing: border-box;
border: none ;
border-radius: 0 ;
}
/* Keep detail section content anchored at top */
.contactPane .detailSection {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
.contactPane .detailsSectionContent {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
/* ── Button section: horizontal scrollable row ──────────────── */
.contactPane .buttonSection {
display: flex;
flex-wrap: nowrap;
align-items: center;
padding: var(--spacing-sm);
padding-bottom: 0;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
margin-bottom: 0;
}
@media (max-width: 1000px) {
.contactPane .buttonSection {
position: sticky;
top: 0;
z-index: 2;
background: var(--color-section-bg);
box-shadow: 0 2px 4px -2px rgba(0,0,0,0.04);
}
}
.contactPane .buttonSection::-webkit-scrollbar {
height: 6px;
}
.contactPane .buttonSection::-webkit-scrollbar-thumb {
background: var(--color-border-pale);
border-radius: var(--border-radius-base);
}
.contactPane .buttonSection::-webkit-scrollbar-track {
background: transparent;
}
.contactPane .buttonSection .selected {
background: none ;
}
.contactPane .groupButtonsList {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: var(--spacing-xs);
list-style: none;
}
.contactPane .buttonSection .groupButtonsList {
margin-left: var(--spacing-xs);
margin-right: var(--spacing-xs);
padding-left: 0;
}
.contactPane .groupButtonsList li {
flex-shrink: 0;
}
.contactPane .groupButtonsList button {
white-space: nowrap;
flex-shrink: 0;
min-width: max-content;
margin-left: 0;
}
/* Groups list in details section — flexible 2-column grid */
.contactPane .detailsSectionContent .groupButtonsList {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: var(--spacing-sm);
list-style: none;
padding: 0;
width: 100%;
box-sizing: border-box;
}
.contactPane .detailsSectionContent .groupButtonsList li {
width: 100%;
aspect-ratio: auto;
display: flex;
flex-direction: column;
align-items: stretch;
gap: var(--spacing-xs);
}
.contactPane .detailsSectionContent .groupButtonsList button {
width: 100%;
height: auto;
text-align: center;
border-radius: var(--border-radius-base);
word-wrap: break-word;
overflow-wrap: break-word;
}
.contactPane .detailsSectionContent .groupButtonsList li > img.hoverControlHide,
.contactPane .detailsSectionContent .groupButtonsList li > img[data-testid="deleteButtonWithCheck"] {
display: block;
align-self: flex-end;
float: none ;
margin: 0 ;
}
@media (max-width: 599px) {
.contactPane .detailsSectionContent .groupButtonsList {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-xs);
}
.contactPane .detailsSectionContent .groupButtonsList button {
font-size: var(--font-size-sm);
border-radius: var(--border-radius-base);
}
}
@media (min-width: 900px) {
.contactPane .detailsSectionContent .groupButtonsList {
grid-template-columns: repeat(3, 1fr);
}
}
.contactPane .detailsSectionContent .newGroupBtn {
width: 100%;
box-sizing: border-box;
margin-top: var(--spacing-sm);
}
.contactPane .detailsSectionContent h3 {
font-size: var(--font-size-xl);
margin-bottom: var(--spacing-sm);
padding-left: 0;
}
/* Delete confirmation POPUP — centered overlay in details section */
.contactPane .detailSection {
position: relative;
}
.contactPane .webidControl div[style*="position: relative"]:has(> div[style*="display: grid"]) {
position: static ;
}
.contactPane .webidControl .personaRow--webid td > div[style*="position: relative"] > div,
.contactPane .detailsSectionContent .groupButtonsList li > div[style*="position: relative"] > div,
.contactPane .detailsSectionContent .contact-toolbar > div[style*="position: relative"] > div {
position: absolute ;
left: auto ;
z-index: 9999 ;
display: grid ;
pointer-events: auto ;
opacity: 1 ;
visibility: visible ;
padding: var(--spacing-btn) ;
min-width: 12em ;
background: var(--color-background) ;
border: var(--border-width-sm) solid var(--color-primary) ;
border-radius: var(--border-radius-base) ;
box-shadow: var(--box-shadow-popup) ;
grid-template-columns: auto auto ;
gap: var(--spacing-xxs) ;
}
.contactPane .detailsSectionContent .contact-toolbar > div[style*="position: relative"] > div > button:has(> img[src$=".svg"]),
.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*="position: relative"] > div > button:has(> img[src$=".svg"]),
.contactPane .webidControl .personaRow--webid td > div[style*="position: relative"] > div > button:has(> img[src$=".svg"]) {
background-color: transparent ;
}
/* Selected state for All contacts button */
.contactPane .allGroupsButton--selected {
background-color: var(--color-primary);
color: var(--color-background);
}
/* ── Header section ──────────────────────────────────────────── */
.contactPane .headerSection {
background: var(--color-background);
padding: var(--spacing-sm);
border-top-left-radius: var(--border-radius-full);
border-top-right-radius: var(--border-radius-full);
margin-bottom: 0;
}
.contactPane .headerSection header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0;
}
.contactPane .headerSection h2 {
margin-bottom: 0;
}
/* ── Dotted horizontal rule ─────────────────────────────────── */
.contactPane .dottedHr {
border: none;
border-top: var(--border-width-sm, 0.1rem) dotted var(--color-text-muted);
margin: 0;
}
/* ── Search section ─────────────────────────────────────────── */
.contactPane .searchSection {
padding: var(--spacing-sm);
padding-bottom: 0;
margin-bottom: 0;
}
/* ── People list section ────────────────────────────────────── */
.contactPane .peopleSection {
display: flex;
background: var(--color-background);
border-top: 1px dotted var(--color-text-muted);
margin-bottom: 0;
}
.contactPane .peopleSection ul {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
max-height: 70vh;
overflow-y: auto;
}
.contactPane .peopleSection li {
border-top: var(--border-width-sm, 0.1rem) solid var(--color-border-pale);
padding: var(--spacing-xs);
}
/* ── Person list item (addressBookPresenter) ─────────────────── */
.contactPane .personLi-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.contactPane .personLi-avatar {
width: 2.813rem /* 45px */;
height: 2.813rem /* 45px */;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.contactPane .personLi-avatar .avatar-placeholder {
width: 2.25rem /* 36px */;
height: 2.25rem /* 36px */;
display: flex;
align-items: center;
justify-content: center;
}
.contactPane .personLi-avatar img {
width: 2.5rem /* 40px */;
height: 2.5rem /* 40px */;
border-radius: 50%;
object-fit: cover;
}
.contactPane .personLi-info {
flex: 1;
margin-left: var(--spacing-sm);
overflow: hidden;
}
.contactPane .personLi-name {
font-weight: bold;
font-size: var(--font-size-base);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.contactPane .personLi-arrow {
margin-left: auto;
display: flex;
align-items: center;
}
.contactPane .personLi--error {
opacity: 0.5;
}