diff options
-rw-r--r-- | css/ContactDetails.scss | 25 | ||||
-rw-r--r-- | css/ContactDetailsAvatar.scss | 96 | ||||
-rw-r--r-- | css/Properties/Properties.scss | 46 | ||||
-rw-r--r-- | css/Properties/PropertyTitle.scss | 2 | ||||
-rw-r--r-- | css/Settings/SettingsAddressbookShares.scss | 2 | ||||
-rw-r--r-- | css/SettingsSection.scss | 4 | ||||
-rw-r--r-- | src/components/ContactDetails/ContactDetailsAvatar.vue | 24 | ||||
-rw-r--r-- | src/components/Properties/PropertySelect.vue | 2 | ||||
-rw-r--r-- | src/components/Properties/PropertyTitle.vue | 4 | ||||
-rw-r--r-- | src/components/Settings/SettingsImportContacts.vue | 2 | ||||
-rw-r--r-- | src/store/contacts.js | 2 |
11 files changed, 119 insertions, 90 deletions
diff --git a/css/ContactDetails.scss b/css/ContactDetails.scss index 451bb4da..47464166 100644 --- a/css/ContactDetails.scss +++ b/css/ContactDetails.scss @@ -33,10 +33,11 @@ #contact-header-infos { display: flex; flex-direction: column; - flex: 1 1; + flex: 1 1 auto; // shrink avatar before this one h2, #details-org-container { display: flex; + flex-wrap: wrap; margin: 0; } input { @@ -44,14 +45,15 @@ color: #fff !important; text-shadow: 0 0 2px var(--color-box-shadow); background: transparent; - border: none; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; - max-width: 100%; + border: none; margin: 0; padding: 4px 5px; flex: 1 1; + min-width: 100px; + max-width: 100%; &::placeholder { color: #fff !important; opacity: .8; @@ -59,7 +61,6 @@ } #contact-org { max-width: 20%; - min-width: 10vw; } } @@ -93,15 +94,25 @@ } } - $grid-column-width: 380px; + $grid-column-gap: 20px; + $grid-column-width: 350px; // contact details section.contact-details { display: grid; /* unquote is a strange hack to avoid removal of the comma by the scss compiler */ grid-template-columns: repeat(auto-fit, minmax(unquote('#{$grid-column-width}'), 1fr)); - grid-column-gap: 20px; - padding: 0 20px; + grid-column-gap: $grid-column-gap; + padding: 0 $grid-column-gap; min-height: 200px; } + + // single column fix, better visual + @media only screen and (max-width: $navigation-width + $list-min-width + 2 * $grid-column-gap +$grid-column-width) { + section.contact-details { + grid-template-columns: 1fr; + grid-column-gap: 10px; + padding: 0 10px; + } + } }
\ No newline at end of file diff --git a/css/ContactDetailsAvatar.scss b/css/ContactDetailsAvatar.scss index 34920f37..b8d1ec8e 100644 --- a/css/ContactDetailsAvatar.scss +++ b/css/ContactDetailsAvatar.scss @@ -24,12 +24,20 @@ // AVATAR .contact-header-avatar { position: relative; - height: 75px; - width: 75px; - border-radius: 50%; - overflow: hidden; - flex-shrink: 0; - margin: 0 22px 0 44px; + flex: 1 1 75px; + min-width: 75px; + max-width: 120px; + margin: 10px; + + // Wrap and cut + &__wrapper { + position: relative; + width: 75px; + height: 75px; + margin-left: auto; + overflow: hidden; + border-radius: 50%; + } &__background { opacity: .2; z-index: 0; @@ -70,46 +78,46 @@ } .contact-header-avatar.maximised { - position: fixed; - height: 100%; - width: 100%; - top: 0; - left: 0; - border-radius: 0; - margin: 0px; - background-color: rgba(0, 0, 0, 0.9); - display: flex; - justify-content: center; - z-index: 200; - padding-top: $header-height; - flex-direction: column; - .contact-header-avatar__photo { - border-radius: 0; - align-self: center; - background-size: contain; - margin: 50px; - } - label.icon-upload-white { - width: 25%; - height: 40px; - position: relative; - } - .contact-header-avatar__options { - height: 50px; + .contact-header-avatar__wrapper { + position: fixed; + height: 100%; width: 100%; + top: 0; + left: 0; + border-radius: 0; + margin: 0px; + background-color: rgba(0, 0, 0, 0.9); display: flex; - opacity: 1; - flex-wrap: wrap; - justify-content: space-evenly; - } - .contact-header-avatar__options > [class^='icon-'] { - width: 25%; - display: block; - cursor: pointer; - opacity: 0.5; - } - .contact-header-avatar__options > [class^='icon-']:hover { - opacity: 0.8; + justify-content: center; + z-index: 200; + padding-top: $header-height; + flex-direction: column; + .contact-header-avatar__photo { + border-radius: 0; + align-self: center; + background-size: contain; + margin: 50px; + } + label.icon-upload-white { + position: relative; + } + .contact-header-avatar__options { + height: 50px; + width: 100%; + display: flex; + flex: 0 0 50px; + opacity: 1; + justify-content: space-evenly; + } + .contact-header-avatar__options > [class^='icon-'] { + width: 25%; + display: block; + cursor: pointer; + opacity: 0.5; + } + .contact-header-avatar__options > [class^='icon-']:hover { + opacity: 0.8; + } } } diff --git a/css/Properties/Properties.scss b/css/Properties/Properties.scss index d27ee5f8..e22cb5b8 100644 --- a/css/Properties/Properties.scss +++ b/css/Properties/Properties.scss @@ -19,14 +19,20 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ +$property-label-min-width: 60px; +$property-label-max-width: 2 * $property-label-min-width; +$property-value-max-width: 250px; .property { @include generate-grid-span(1); - display: flex; - flex-wrap: wrap; - flex-direction: column; position: relative; - width: $grid-column-width; + padding-right: 44px; // delete button + // we need this to keep the alignment of the ext and delete button + // The flex grow will never go over those values. Therefore we can set + // the max width and keep the right alignment + max-width: $property-label-max-width + $property-value-max-width + 44px; + justify-self: center; + width: 100%; &--last { margin-bottom: $grid-height-unit; @@ -40,26 +46,24 @@ &__row { display: flex; align-items: center; - padding-right: 44px; position: relative; } // property label or multiselect within row &__label, - &__label.multiselect.multiselect-vue { - margin: $grid-input-margin; + &__label.multiselect { margin: $grid-input-margin 5px $grid-input-margin 0; - height: $grid-input-height-with-margin; padding: $grid-input-padding 0; - width: 120px; + flex: 1 0; // min width is 60px, let's grow until 120px + height: $grid-input-height-with-margin; + width: $property-label-min-width !important; // override multiselect + min-width: $property-label-min-width; + max-width: $property-label-max-width; + opacity: .7; user-select: none; background-size: 16px; - .multiselect__tags { - border-color: transparent; - } - &, .multiselect__input::placeholder { text-align: right; @@ -95,18 +99,22 @@ &__label.multiselect { .multiselect__tags { - border: none; + border: none !important; // override multiselect .multiselect__single { background-repeat: no-repeat; background-position: center right 4px; padding-right: 24px; } + .multiselect__content-wrapper { + min-width: $property-label-max-width; // improve readability on narrow screens + } } } // Property value within row, after label &__value { - flex: 1 1; + flex: 1 1 $property-value-max-width; + max-width: $property-value-max-width; textarea& { align-self: flex-start; @@ -141,8 +149,8 @@ // External link (tel, mailto, http, ftp...) &__ext { position: absolute; - // property row rightPadding + 8px; - right: 52px; + // 8px padding + right: 8px; opacity: 0; &:hover, &:focus, @@ -150,7 +158,7 @@ opacity: .7; // still show the delete button for keyboard accessibility ~ .property__delete { - opacity: .7; + opacity: .5; } } } @@ -159,7 +167,7 @@ &__delete { position: absolute; top: 0; - right: 0; + left: 100%; width: $grid-height-unit; height: $grid-height-unit; margin: 0; diff --git a/css/Properties/PropertyTitle.scss b/css/Properties/PropertyTitle.scss index 3c4912b0..63c30c66 100644 --- a/css/Properties/PropertyTitle.scss +++ b/css/Properties/PropertyTitle.scss @@ -30,7 +30,7 @@ .property__title--icon { background-position: center right; } - .icon-details { + .property__title--icon-details { margin-left: 7px; } }
\ No newline at end of file diff --git a/css/Settings/SettingsAddressbookShares.scss b/css/Settings/SettingsAddressbookShares.scss index f0bd169c..3d602604 100644 --- a/css/Settings/SettingsAddressbookShares.scss +++ b/css/Settings/SettingsAddressbookShares.scss @@ -41,7 +41,7 @@ width: 14px; } - .multiselect.multiselect-vue { + .multiselect { width: inherit; margin: 0; .multiselect__tags:focus-within, diff --git a/css/SettingsSection.scss b/css/SettingsSection.scss index 561036df..09953f39 100644 --- a/css/SettingsSection.scss +++ b/css/SettingsSection.scss @@ -40,7 +40,7 @@ // Sort Contacts .sort-contacts { - .multiselect.multiselect-vue { + .multiselect { width: 100%; margin: 0; .multiselect__single { @@ -68,7 +68,7 @@ border-radius: var(--border-radius); } } - &__multiselect.multiselect.multiselect-vue { + &__multiselect.multiselect { width: 100%; margin: 0; margin-top: -1px; diff --git a/src/components/ContactDetails/ContactDetailsAvatar.vue b/src/components/ContactDetails/ContactDetailsAvatar.vue index df0a3c45..c142c82f 100644 --- a/src/components/ContactDetails/ContactDetailsAvatar.vue +++ b/src/components/ContactDetails/ContactDetailsAvatar.vue @@ -23,17 +23,19 @@ import rfcProps from '../../models/rfcProps'; <template> <div :class="{'maximised':maximizeAvatar }" class="contact-header-avatar"> - <div class="contact-header-avatar__background" @click="toggleSize" /> - <div v-if="contact.photo" :style="{ 'backgroundImage': `url(${contact.photo})` }" - class="contact-header-avatar__photo" - @click="toggleSize" /> - <div class="contact-header-avatar__options"> - <input id="contact-avatar-upload" type="file" class="hidden" - accept="image/*" @change="processFile"> - <label v-tooltip.auto="t('contacts', 'Upload a new picture')" v-if="!contact.addressbook.readOnly" - for="contact-avatar-upload" class="icon-upload-white" @click="processFile" /> - <div v-if="maximizeAvatar && !contact.addressbook.readOnly" class="icon-delete-white" @click="removePhoto" /> - <a v-if="maximizeAvatar" :href="contact.url + '?photo'" class="icon-download-white" /> + <div class="contact-header-avatar__wrapper"> + <div class="contact-header-avatar__background" @click="toggleSize" /> + <div v-if="contact.photo" :style="{ 'backgroundImage': `url(${contact.photo})` }" + class="contact-header-avatar__photo" + @click="toggleSize" /> + <div class="contact-header-avatar__options"> + <input id="contact-avatar-upload" type="file" class="hidden" + accept="image/*" @change="processFile"> + <label v-tooltip.auto="t('contacts', 'Upload a new picture')" v-if="!contact.addressbook.readOnly" + for="contact-avatar-upload" class="icon-upload-white" @click="processFile" /> + <div v-if="maximizeAvatar && !contact.addressbook.readOnly" class="icon-delete-white" @click="removePhoto" /> + <a v-if="maximizeAvatar" :href="contact.url + '?photo'" class="icon-download-white" /> + </div> </div> </div> </template> diff --git a/src/components/Properties/PropertySelect.vue b/src/components/Properties/PropertySelect.vue index 5c2b4d4b..7729c0f3 100644 --- a/src/components/Properties/PropertySelect.vue +++ b/src/components/Properties/PropertySelect.vue @@ -39,7 +39,7 @@ @click="deleteProperty" /> <multiselect v-model="matchedOptions" :options="propModel.options" :placeholder="t('contacts', 'Select option')" - :disabled="isSingleOption || isReadOnly" class="multiselect-vue property__value" track-by="id" + :disabled="isSingleOption || isReadOnly" class="property__value" track-by="id" label="name" @input="updateValue" /> </div> </div> diff --git a/src/components/Properties/PropertyTitle.vue b/src/components/Properties/PropertyTitle.vue index 8c6341d4..b297aa42 100644 --- a/src/components/Properties/PropertyTitle.vue +++ b/src/components/Properties/PropertyTitle.vue @@ -23,9 +23,9 @@ <template> <h3 class="property__title property__row"> <div :class="icon" class="property__label property__title--icon" /> - {{ readableName }} + <span class="property__value">{{ readableName }}</span> <!-- display tooltip with hint if available --> - <div v-tooltip.auto="info" v-if="info" class="icon-details" /> + <div v-tooltip.auto="info" v-if="info" class="property__title--icon-details icon-details" /> </h3> </template> diff --git a/src/components/Settings/SettingsImportContacts.vue b/src/components/Settings/SettingsImportContacts.vue index 4b2bf745..a9b44516 100644 --- a/src/components/Settings/SettingsImportContacts.vue +++ b/src/components/Settings/SettingsImportContacts.vue @@ -34,7 +34,7 @@ :disabled="isSingleAddressbook || isImporting" :placeholder="t('contacts', 'Contacts')" label="displayName" - class="multiselect-vue import-contact__multiselect" /> + class="import-contact__multiselect" /> </template> <button v-else id="upload" for="contact-import" class="button import-contact__multiselect-label import-contact__multiselect--no-select icon-error"> diff --git a/src/store/contacts.js b/src/store/contacts.js index 0bcd8cc1..cc06753d 100644 --- a/src/store/contacts.js +++ b/src/store/contacts.js @@ -26,7 +26,7 @@ import Contact from '../models/contact' const state = { // Using objects for performance - // https://jsperf.com/ensure-unique-id-objects-vs-array + // https://codepen.io/skjnldsv/pen/ZmKvQo contacts: {}, sortedContacts: [], orderKey: 'displayName' |