fix build

Update icon size enum & class
This commit is contained in:
yoy 2025-09-05 15:04:29 +02:00
parent 35debcaba5
commit c64f8eb786
92 changed files with 346 additions and 330 deletions

View file

@ -142,7 +142,7 @@ export class RemindersEditor implements Component<RemindersEditorAttrs> {
},
m(Icon, {
icon: Icons.Cancel,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: getColors(ButtonColor.Content).button,
},

View file

@ -9,7 +9,7 @@ import { RecipientsSearchModel } from "../../../../common/misc/RecipientsSearchM
import { Guest } from "../../view/CalendarInvites.js"
import { theme } from "../../../../common/gui/theme.js"
import { IconButton } from "../../../../common/gui/base/IconButton.js"
import { px, size } from "../../../../common/gui/size.js"
import { component_size, px, size } from "../../../../common/gui/size.js"
import { CalendarEventWhoModel } from "../eventeditor-model/CalendarEventWhoModel.js"
import { LoginController } from "../../../../common/api/main/LoginController.js"
import { CalendarEventModel, CalendarOperation } from "../eventeditor-model/CalendarEventModel.js"
@ -363,7 +363,7 @@ export class AttendeeListEditor implements Component<AttendeeListEditorAttrs> {
{
style: {
paddingLeft: px(size.hpad_medium + size.vpad_small),
paddingRight: px((size.button_height - size.button_height_compact) / 2),
paddingRight: px((component_size.button_height - component_size.button_height_compact) / 2),
},
},
[

View file

@ -375,7 +375,7 @@ export class CalendarEventEditView implements Component<CalendarEventEditViewAtt
icon: Icons.Clock,
style: { fill: getColors(ButtonColor.Content).button },
title: lang.get("reminderBeforeEvent_label"),
size: IconSize.Medium,
size: IconSize.PX24,
}),
],
),

View file

@ -40,7 +40,7 @@ export class EventTimeEditor implements Component<EventTimeEditorAttrs> {
fill: theme.on_surface,
},
title: lang.get("timeSection_label"),
size: IconSize.Medium,
size: IconSize.PX24,
}),
m(
Switch,

View file

@ -60,7 +60,7 @@ export class ContactPreviewView implements Component<ContactPreviewViewAttrs> {
return m(Icon, {
icon,
class: "pr",
size: IconSize.Medium,
size: IconSize.PX24,
style: Object.assign(
{
fill: theme.on_surface,

View file

@ -134,7 +134,7 @@ export class EventPreviewView implements Component<EventPreviewViewAttrs> {
private renderSectionIndicator(icon: AllIcons, style: Record<string, any> = {}): Children {
return m(Icon, {
icon,
size: IconSize.Medium,
size: IconSize.PX24,
style: Object.assign(
{
fill: theme.on_surface_variant,

View file

@ -1,5 +1,5 @@
import m, { Component, Vnode } from "mithril"
import { px, size } from "../../../common/gui/size"
import { component_size, px, size } from "../../../common/gui/size"
import stream from "mithril/stream"
import Stream from "mithril/stream"
import type { PositionRect } from "../../../common/gui/base/Overlay"
@ -265,14 +265,14 @@ export class CalendarSearchBar implements Component<CalendarSearchBarAttrs> {
}
} else if (window.innerWidth < 500) {
overlayRect = {
top: px(size.navbar_height_mobile + 6),
top: px(component_size.navbar_height_mobile + 6),
left: px(16),
right: px(16),
zIndex: LayerType.LowPriorityOverlay,
}
} else {
overlayRect = {
top: px(size.navbar_height_mobile + 6),
top: px(component_size.navbar_height_mobile + 6),
left: px(domRect.left),
right: px(window.innerWidth - domRect.right),
zIndex: LayerType.LowPriorityOverlay,

View file

@ -31,7 +31,7 @@ export class CalendarSearchBarOverlay implements Component<CalendarSearchBarOver
{
style: {
height: px(52),
"border-left": px(size.border_selection) + " solid transparent",
"border-left": px(size.radius_4) + " solid transparent",
},
// avoid closing overlay before the click event can be received
onmousedown: (e: MouseEvent) => e.preventDefault(),

View file

@ -2,7 +2,7 @@ import m, { Children, Component, Vnode } from "mithril"
import { assertMainOrNode } from "../../../../common/api/common/Env"
import { downcast } from "@tutao/tutanota-utils"
import { List, ListAttrs, MultiselectMode, RenderConfig } from "../../../../common/gui/base/List.js"
import { size } from "../../../../common/gui/size.js"
import { component_size, size } from "../../../../common/gui/size.js"
import { CalendarEvent } from "../../../../common/api/entities/tutanota/TypeRefs.js"
import ColumnEmptyMessageBox from "../../../../common/gui/base/ColumnEmptyMessageBox.js"
import { BootIcons } from "../../../../common/gui/base/icons/BootIcons.js"
@ -78,7 +78,7 @@ export class CalendarSearchListView implements Component<CalendarSearchListViewA
}
private readonly calendarRenderConfig: RenderConfig<CalendarSearchResultListEntry, SearchResultListRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Disabled,
swipe: null,
createElement: (dom: HTMLElement) => {

View file

@ -15,7 +15,7 @@ import { BootIcons } from "../../../common/gui/base/icons/BootIcons.js"
import { LoginSettingsViewer } from "../../../common/settings/login/LoginSettingsViewer.js"
import { Icons } from "../../../common/gui/base/icons/Icons.js"
import { AppearanceSettingsViewer } from "../../../common/settings/AppearanceSettingsViewer.js"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { lang, MaybeTranslation } from "../../../common/misc/LanguageViewModel.js"
import { BackgroundColumnLayout } from "../../../common/gui/BackgroundColumnLayout.js"
import { theme } from "../../../common/gui/theme.js"
@ -164,7 +164,7 @@ export class CalendarSettingsView extends BaseTopLevelView implements TopLevelVi
class: this.isTabletView() ? "border-radius-top-left-big" : "",
style: this.isTabletView()
? {
"margin-top": px(size.navbar_height_mobile + size.vpad_small),
"margin-top": px(component_size.navbar_height_mobile + size.vpad_small),
}
: {},
},
@ -221,7 +221,7 @@ export class CalendarSettingsView extends BaseTopLevelView implements TopLevelVi
text: m(".pl-s", lang.getTranslation("supportMenu_label").text),
icon: m(Icon, {
icon: Icons.SpeechBubbleFill,
size: IconSize.Medium,
size: IconSize.PX24,
class: "center-h",
container: "div",
style: { fill: theme.on_surface_variant },

View file

@ -1,6 +1,6 @@
import { CalendarNavConfiguration, getIconForViewType } from "../gui/CalendarGuiUtils.js"
import m, { Children, Component, Vnode } from "mithril"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { lang, MaybeTranslation } from "../../../common/misc/LanguageViewModel.js"
import { IconSegmentControl } from "../../../common/gui/base/IconSegmentControl.js"
import { AllIcons } from "../../../common/gui/base/Icon.js"
@ -81,7 +81,7 @@ export class CalendarDesktopToolbar implements Component<CalendarDesktopToolbarA
left: 0,
right: 0,
// need explicit width to center the control
width: px(size.icon_segment_control_button_width * 4),
width: px(component_size.icon_segment_control_button_width * 4),
},
},
m(IconSegmentControl, {

View file

@ -64,7 +64,7 @@ import { styles } from "../../../common/gui/styles"
import { MultiDayCalendarView } from "./MultiDayCalendarView"
import { Dialog } from "../../../common/gui/base/Dialog"
import { isApp, isDesktop } from "../../../common/api/common/Env"
import { px, size } from "../../../common/gui/size"
import { component_size, px, size } from "../../../common/gui/size"
import { FolderColumnView } from "../../../common/gui/FolderColumnView.js"
import { deviceConfig } from "../../../common/misc/DeviceConfig"
import { exportCalendar, handleCalendarImport } from "../../../common/calendar/gui/CalendarImporterDialog.js"
@ -1095,7 +1095,7 @@ export class CalendarView extends BaseTopLevelView implements TopLevelView<Calen
? m(Icon, {
title: lastSyncStr,
icon: Icons.SyncProblem,
size: IconSize.Medium,
size: IconSize.PX24,
class: "pr-s",
style: {
fill: theme.on_surface_variant,
@ -1534,7 +1534,7 @@ export class CalendarView extends BaseTopLevelView implements TopLevelView<Calen
// side of month's name, so we hardcoded the left spacing to be the same used by the month name, so doesn't matter
// if the user clicks on month's name or on the icon
// noinspection JSSuspiciousNameCombination
const elementRect = { ...dom.getBoundingClientRect(), left: size.button_height }
const elementRect = { ...dom.getBoundingClientRect(), left: component_size.button_height }
const selector = new DaySelectorPopup(elementRect, {
selectedDate: getStartOfDay(this.viewModel.selectedDate()),

View file

@ -18,7 +18,7 @@ export class TodayIconButton implements Component<TodayIconButtonAttrs> {
icon: m(Icon, {
container: "div",
class: "center-h svg-text-content-bg",
size: IconSize.Medium,
size: IconSize.PX24,
svgParameters: { date: new Date().getDate().toString() },
icon: Icons.Today,
style: {

View file

@ -26,7 +26,7 @@ export class SettingsNavButton implements Component<SettingsNavButtonAttrs> {
icon: attrs.icon?.(),
container: "div",
class: "center-h",
size: IconSize.Large,
size: IconSize.PX20,
})
: null,
onclick: attrs.click,
@ -36,7 +36,7 @@ export class SettingsNavButton implements Component<SettingsNavButtonAttrs> {
icon: Icons.ArrowForward,
container: "div",
class: "center-h items-ends",
size: IconSize.Large,
size: IconSize.PX20,
}),
)

View file

@ -8,7 +8,7 @@ import { Dialog, DialogType } from "../../gui/base/Dialog.js"
import { lang, MaybeTranslation } from "../../misc/LanguageViewModel.js"
import { List, ListAttrs, ListLoadingState, MultiselectMode, RenderConfig } from "../../gui/base/List.js"
import { KindaCalendarRow } from "../../../calendar-app/calendar/gui/CalendarRow.js"
import { size } from "../../gui/size.js"
import { component_size, size } from "../../gui/size.js"
import { DialogHeaderBar } from "../../gui/base/DialogHeaderBar.js"
import { ButtonType } from "../../gui/base/Button.js"
import m from "mithril"
@ -54,7 +54,7 @@ export function parseCalendarFile(file: DataFile): ParsedCalendarData {
*/
export function showEventsImportDialog(events: CalendarEvent[], okAction: (dialog: Dialog) => unknown, title: MaybeTranslation) {
const renderConfig: RenderConfig<CalendarEvent, KindaCalendarRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Disabled,
swipe: null,
createElement: (dom) => {

View file

@ -230,7 +230,6 @@ export class TimeView implements Component<TimeViewAttributes> {
icon: hasAnyConflict ? Icons.AlertCircle : Icons.Checkmark,
container: "div",
class: "mr-xxs",
size: IconSize.Normal,
style: {
fill: hasAnyConflict ? theme.on_warning_container : theme.on_success_container,
},

View file

@ -1,6 +1,6 @@
import { pureComponent } from "./base/PureComponent.js"
import m, { Children } from "mithril"
import { px, size } from "./size.js"
import { component_size, px, size } from "./size.js"
export interface BaseMobileHeaderAttrs {
left?: Children
@ -17,7 +17,7 @@ export const BaseMobileHeader = pureComponent(({ left, center, right, injections
".flex.items-center.rel.button-height.mt-safe-inset.plr-safe-inset.noprint",
{
style: {
height: px(size.navbar_height_mobile),
height: px(component_size.navbar_height_mobile),
},
},
[

View file

@ -1,6 +1,6 @@
import { pureComponent } from "./base/PureComponent.js"
import m from "mithril"
import { px, size } from "./size.js"
import { component_size, px, size } from "./size.js"
import { responsiveCardHMargin } from "./cards.js"
/** Toolbar layout that is used in the second/list column. */
@ -9,7 +9,7 @@ export const DesktopListToolbar = pureComponent((__, children) => {
".flex.pt-xs.pb-xs.items-center.list-bg",
{
style: {
"border-radius": `${size.border_radius}px 0 0 ${size.border_radius}px`,
"border-radius": `${size.radius_8}px 0 0 ${size.radius_8}px`,
// matching the list
marginLeft: `5px`,
marginBottom: px(size.hpad_large),
@ -40,12 +40,12 @@ export const DesktopViewerToolbar = pureComponent((__, children) => {
".flex.list-bg.pt-xs.pb-xs.plr-m",
{
style: {
"border-radius": `0 ${size.border_radius_larger}px ${size.border_radius_larger}px 0`,
"border-radius": `0 ${size.radius_8}px ${size.radius_8}px 0`,
},
},
[
// Height keeps the toolbar showing for consistency, even if there are no actions
m(".flex-grow", { style: { height: px(size.button_height) } }),
m(".flex-grow", { style: { height: px(component_size.button_height) } }),
children,
],
),

View file

@ -1,7 +1,7 @@
import m, { Children, ClassComponent, Vnode } from "mithril"
import { BubbleTextField, BubbleTextFieldAttrs, BubbleTextFieldClickBehaviour } from "./base/BubbleTextField.js"
import { Recipient } from "../api/common/recipients/Recipient.js"
import { px, size } from "./size.js"
import { component_size, px, size } from "./size.js"
import { Icon, IconSize, progressIcon } from "./base/Icon.js"
import { lang, TranslationKey } from "../misc/LanguageViewModel.js"
import { stringToNameAndMailAddress } from "../misc/parsing/MailAddressParser.js"
@ -80,7 +80,7 @@ export class MailRecipientsTextField implements ClassComponent<MailRecipientsTex
if (recipient.verificationState === PresentableKeyVerificationState.ALERT) {
return m(Icon, {
icon: Icons.BrokenShield,
size: IconSize.Large, // we want 20px
size: IconSize.PX20, // we want 20px
style: {
fill: theme.error,
position: "relative",
@ -91,7 +91,7 @@ export class MailRecipientsTextField implements ClassComponent<MailRecipientsTex
} else if (recipient.verificationState === PresentableKeyVerificationState.SECURE) {
return m(Icon, {
icon: Icons.Shield,
size: IconSize.Large,
size: IconSize.PX20,
style: {
fill: theme.success,
position: "relative",
@ -161,7 +161,7 @@ export class MailRecipientsTextField implements ClassComponent<MailRecipientsTex
{
style: {
width: px(20), // in case the progress icon is not shown we reserve the width of the progress icon
height: px(size.button_height_compact),
height: px(component_size.button_height_compact),
},
},
attrs.search.isLoading() ? progressIcon() : null,

View file

@ -2,7 +2,7 @@ import { lang, TranslationKey } from "../misc/LanguageViewModel.js"
import { ClickHandler } from "./base/GuiUtils.js"
import m, { Children, Component, Vnode } from "mithril"
import { theme } from "./theme.js"
import { px, size } from "./size.js"
import { component_size, px, size } from "./size.js"
import { BaseButton, BaseButtonAttrs } from "./base/buttons/BaseButton.js"
import { boxShadowLow } from "./main-styles.js"
@ -24,7 +24,7 @@ export class MainCreateButton implements Component<MainCreateButtonAttrs> {
class: `full-width border-radius-big center b flash ${vnode.attrs.class}`,
style: {
// matching toolbar
height: px(size.button_height + size.vpad_xs * 2),
height: px(component_size.button_height + size.vpad_xs * 2),
"background-color": theme.primary_container,
color: theme.on_primary_container,
"box-shadow": boxShadowLow,

View file

@ -1,7 +1,7 @@
import m, { Children, Component } from "mithril"
import type { PositionRect } from "./base/Overlay"
import { displayOverlay } from "./base/Overlay"
import { px, size } from "./size"
import { component_size, px, size } from "./size"
import { Icons } from "./base/icons/Icons"
import { assertMainOrNode } from "../api/common/Env"
import { lang } from "../misc/LanguageViewModel"
@ -61,9 +61,9 @@ export class SearchInPageOverlay {
}
private getRect(): PositionRect {
const bottomNavHeight = size.bottom_nav_bar + getSafeAreaInsetBottom()
const bottomNavHeight = component_size.bottom_nav_bar + getSafeAreaInsetBottom()
return {
height: px(size.navbar_height_mobile),
height: px(component_size.navbar_height_mobile),
// Place the search overlay on top of the bottom nav bar
bottom: px(styles.isUsingBottomNavigation() ? -bottomNavHeight : 0),
right: px(0),
@ -95,7 +95,7 @@ export class SearchInPageOverlay {
style: {
width: px(250),
top: 0,
height: px(size.button_height),
height: px(component_size.button_height),
left: 0,
},
},

View file

@ -27,7 +27,7 @@ export class TitleSection implements Component<SettingsTitleSectionAttrsType> {
attrs.icon
? m(Icon, {
icon: attrs.icon,
size: IconSize.XXL,
size: IconSize.PX64,
style: {
fill: attrs.iconOptions?.color,
},

View file

@ -57,7 +57,7 @@ export class BaseSearchBar implements ClassComponent<BaseSearchBarAttrs> {
styles.isDesktopLayout()
? m(Icon, {
icon: BootIcons.Search,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: theme.on_surface_variant,
},
@ -82,7 +82,7 @@ export class BaseSearchBar implements ClassComponent<BaseSearchBarAttrs> {
label: attrs.busy ? "loading_msg" : "close_alt",
icon: m(Icon, {
container: "div",
size: IconSize.Medium,
size: IconSize.PX24,
icon: attrs.busy ? BootIcons.Progress : Icons.Close,
class: "center-h " + (attrs.busy ? "icon-progress-search icon-progress" : ""),
style: {

View file

@ -5,7 +5,7 @@ import { lang } from "../../misc/LanguageViewModel"
import type { lazy } from "@tutao/tutanota-utils"
import { theme } from "../theme.js"
import { encodeSVG, getOperatingClasses } from "./GuiUtils.js"
import { px, size } from "../size"
import { component_size, px, size } from "../size"
export type CheckboxAttrs = {
label: lazy<string | Children>
@ -30,7 +30,7 @@ export class Checkbox implements Component<CheckboxAttrs> {
`small.block.content-fg${Checkbox.getBreakClass(helpLabelText)}`,
{
style: {
marginLeft: px(size.checkbox_helper_text_margin),
marginLeft: px(component_size.checkbox_helper_text_margin),
},
},
helpLabelText,

View file

@ -27,7 +27,7 @@ export class IconMessageBox implements Component<InfoMessaggeBoxAttrs> {
style: {
fill: attrs.color,
},
class: "icon-message-box",
class: "icon-80",
})
: null,
m(

View file

@ -2,7 +2,7 @@ import m, { Children } from "mithril"
import { modal, ModalComponent } from "./Modal"
import { animations, opacity, transform, TransformEnum } from "../animation/Animations"
import { ease } from "../animation/Easing"
import { px, size } from "../size"
import { component_size, px, size } from "../size"
import { focusNext, focusPrevious, Shortcut } from "../../misc/KeyManager"
import type { ButtonAttrs } from "./Button.js"
import { lang, MaybeTranslation } from "../../misc/LanguageViewModel"
@ -384,7 +384,7 @@ export class Dropdown implements ModalComponent {
}
private getFilterHeight(): number {
return this.isFilterable ? size.button_height + size.vpad_xs : 0
return this.isFilterable ? component_size.button_height + size.vpad_xs : 0
}
}

View file

@ -114,7 +114,7 @@ export class ExpandableTextArea implements ClassComponent<ExpandableTextAreaAttr
? m(Icon, {
icon: BootIcons.Expand,
class: "flex-center items-center abs",
size: IconSize.Medium,
size: IconSize.PX24,
style: {
top: this.initialHeight === 0 ? 0 : px(this.initialHeight / 2 - size.icon_24 / 2),
bottom: this.initialHeight === 0 ? 0 : undefined,

View file

@ -70,7 +70,7 @@ export class ExpanderButton implements Component<ExpanderAttrs> {
m(Icon, {
icon: BootIcons.Expand,
class: "flex-center items-center",
size: a.isBig ? IconSize.Medium : IconSize.Normal,
size: a.isBig ? IconSize.PX24 : undefined,
style: {
fill: a.color ? a.color : theme.on_surface_variant,
"margin-right": px(-4),

View file

@ -5,7 +5,7 @@ import { theme } from "../theme"
import { ClickHandler } from "./GuiUtils"
import { assertNotNull } from "@tutao/tutanota-utils"
import { lang, Translation } from "../../misc/LanguageViewModel"
import { px, size } from "../size"
import { component_size, px, size } from "../size"
export interface FilterChipAttrs {
label: Translation
@ -36,7 +36,7 @@ export class FilterChip implements Component<FilterChipAttrs> {
selectors,
{
style: {
minHeight: px(size.button_icon_bg_size),
minHeight: px(component_size.button_icon_bg_size),
...(selected
? {
background: theme.secondary_container,

View file

@ -12,11 +12,10 @@ assertMainOrNode()
export type AllIcons = BootIcons | Icons
export enum IconSize {
Normal,
Medium,
Large,
XL,
XXL,
PX20,
PX24,
PX32,
PX64,
}
export type IconAttrs = {
@ -122,20 +121,19 @@ export class Icon implements Component<IconAttrs> {
getClass(attrs: IconAttrs): string {
let cls = ""
switch (attrs.size) {
case IconSize.Medium:
cls += "icon-large "
case IconSize.PX24:
cls += "icon-24 "
break
case IconSize.Large:
cls += "icon-medium-large "
case IconSize.PX20:
cls += "icon-20 "
break
case IconSize.XL:
cls += "icon-xl "
case IconSize.PX32:
cls += "icon-32 "
break
case IconSize.XXL:
cls += "icon-xxl "
case IconSize.PX64:
cls += "icon-64 "
break
case IconSize.Normal:
default:
break
}
@ -159,6 +157,6 @@ export class Icon implements Component<IconAttrs> {
export function progressIcon(): Vnode<IconAttrs> {
return m(Icon, {
icon: BootIcons.Progress,
class: "icon-large icon-progress",
class: "icon-24 icon-progress",
})
}

View file

@ -28,7 +28,7 @@ export class IconButton implements Component<IconButtonAttrs> {
icon: attrs.icon,
container: "div",
class: "center-h",
size: attrs.size === ButtonSize.Large ? IconSize.XL : IconSize.Medium,
size: attrs.size === ButtonSize.Large ? IconSize.PX32 : IconSize.PX24,
style: {
fill: getColors(attrs.colors ?? ButtonColor.Content).button,
visibility: attrs.hidden ? "hidden" : "visible",

View file

@ -50,7 +50,7 @@ export class IconSegmentControl<T> implements Component<IconSegmentControlAttrs<
icon: item.icon,
container: "div",
class: "center-h",
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: item.value === vnode.attrs.selectedValue ? theme.on_secondary_container : theme.on_surface_variant,
},

View file

@ -1,6 +1,6 @@
import m, { Children, ClassComponent, Vnode, VnodeDOM } from "mithril"
import { createResizeObserver, debounce, memoized, numberRange } from "@tutao/tutanota-utils"
import { px, size } from "../size.js"
import { component_size, px, size } from "../size.js"
import { isKeyPressed } from "../../misc/KeyManager.js"
import { Keys, TabIndex } from "../../api/common/TutanotaConstants.js"
import { client } from "../../misc/ClientDetector.js"
@ -396,7 +396,7 @@ export class List<T, VH extends ViewHolder<T>> implements ClassComponent<ListAtt
const rowHeight = attrs.renderConfig.itemHeight
// plus loading indicator
// should depend on whether we are completely loaded maybe?
const statusHeight = attrs.state.loadingStatus === ListLoadingState.Done ? 0 : size.list_row_height
const statusHeight = attrs.state.loadingStatus === ListLoadingState.Done ? 0 : component_size.list_row_height
this.innerDom!.style.height = px(attrs.state.items.length * rowHeight + statusHeight)
if (attrs.state.activeIndex != null && attrs.state.activeIndex !== this.activeIndex) {
const index = attrs.state.activeIndex
@ -474,7 +474,7 @@ export class List<T, VH extends ViewHolder<T>> implements ClassComponent<ListAtt
".flex-center.items-center",
{
style: {
height: px(size.list_row_height),
height: px(component_size.list_row_height),
width: "100%",
position: "absolute",
gap: px(size.hpad_small),
@ -495,7 +495,7 @@ export class List<T, VH extends ViewHolder<T>> implements ClassComponent<ListAtt
".plr-l.flex-center.items-center",
{
style: {
height: px(size.list_row_height),
height: px(component_size.list_row_height),
},
},
m(Button, {
@ -525,7 +525,7 @@ export class List<T, VH extends ViewHolder<T>> implements ClassComponent<ListAtt
return m("li.list-row", {
style: {
bottom: 0,
height: px(size.list_row_height),
height: px(component_size.list_row_height),
display: this.shouldDisplayStatusRow() ? "none" : null,
},
oncreate: (vnode) => {

View file

@ -1,6 +1,6 @@
import m, { Children, Component, RouteLinkAttrs, Vnode } from "mithril"
import { handleUncaughtError } from "../../misc/ErrorHandler"
import { px, size } from "../size"
import { component_size, px, size } from "../size"
import type { lazy } from "@tutao/tutanota-utils"
import { lazyStringValue, neverNull } from "@tutao/tutanota-utils"
import type { lazyIcon } from "./Icon"
@ -96,11 +96,11 @@ export class NavButton implements Component<NavButtonAttrs> {
const isSelected = isNavButtonSelected(a)
if (a.colors === NavButtonColor.Header && !styles.isDesktopLayout()) {
return "flex-end items-center icon-xl" + (isSelected ? " selected" : "")
return "flex-end items-center icon-32" + (isSelected ? " selected" : "")
} else if (a.small === true) {
return "flex-center items-center icon" + (isSelected ? " selected" : "")
} else {
return "flex-center items-center icon-large" + (isSelected ? " selected" : "")
return "flex-center items-center icon-24" + (isSelected ? " selected" : "")
}
}
@ -202,7 +202,7 @@ export class NavButton implements Component<NavButtonAttrs> {
}
getHeight(): number {
return size.button_height
return component_size.button_height
}
}

View file

@ -2,7 +2,7 @@ import m, { Children, Component, VnodeDOM } from "mithril"
import { LayerType } from "../../../RootView"
import { lazy, makeSingleUse, newPromise } from "@tutao/tutanota-utils"
import { assertMainOrNodeBoot } from "../../api/common/Env"
import { px, size } from "../size.js"
import { component_size, px, size } from "../size.js"
import { styles } from "../styles.js"
import { getSafeAreaInsetBottom } from "../HtmlUtils.js"
@ -83,7 +83,7 @@ export const overlay: Component<OverlayParentAttrs> = {
display: visible ? "" : "none",
"margin-top": "env(safe-area-inset-top)", // insets for iPhone X
// keep the bottom nav bar clear & inset for iOS
"margin-bottom": styles.isUsingBottomNavigation() ? px(size.bottom_nav_bar + getSafeAreaInsetBottom()) : "unset",
"margin-bottom": styles.isUsingBottomNavigation() ? px(component_size.bottom_nav_bar + getSafeAreaInsetBottom()) : "unset",
// we would need to change this if we wanted something to appear from the side
"margin-left": "env(safe-area-inset-left)",
"margin-right": "env(safe-area-inset-right)",

View file

@ -203,7 +203,7 @@ export class Select<U extends SelectOption<T>, T> implements ClassComponent<Sele
icon: BootIcons.Expand,
container: "div",
class: `fit-content`,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: iconColor ?? getColors(ButtonColor.Content).button,
},

View file

@ -71,7 +71,7 @@ export class SidebarSectionRow implements Component<SidebarSectionRowAttrs> {
".button-height.flex.items-center.plr-button",
m(Icon, {
icon: attrs.icon,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: attrs.iconColor ?? (isNavButtonSelected(navButtonAttrs) ? theme.primary : theme.on_surface_variant),
},

View file

@ -85,13 +85,13 @@ export class SingleLineTextField<T extends TextFieldType> implements ClassCompon
let padding
if (fontSize > 16 && fontSize < 32) {
iconSize = IconSize.Large
iconSize = IconSize.PX20
padding = size.icon_24
} else if (fontSize > 32) {
iconSize = IconSize.XL
iconSize = IconSize.PX32
padding = size.icon_32
} else {
iconSize = IconSize.Medium
iconSize = IconSize.PX24
// FIXME: Replace with size.spacing token
padding = 20
}

View file

@ -1,4 +1,4 @@
import { size } from "../size"
import { component_size, size } from "../size"
export const enum DirectionLock {
Horizontal,
@ -64,7 +64,7 @@ export class SwipeHandler {
if (!this.isAnimating) {
this.onHorizontalDrag(x, y)
} // If we don't have a vertical lock yet but we would like to have it, lock vertically
} else if (this.directionLock !== DirectionLock.Vertical && Math.abs(y) > Math.abs(x) && Math.abs(y) > size.list_row_height) {
} else if (this.directionLock !== DirectionLock.Vertical && Math.abs(y) > Math.abs(x) && Math.abs(y) > component_size.list_row_height) {
this.directionLock = DirectionLock.Vertical
if (!this.isAnimating) {

View file

@ -8,7 +8,7 @@ import type { ClickHandler } from "./GuiUtils"
import { assertMainOrNode } from "../../api/common/Env"
import { IconButton, IconButtonAttrs } from "./IconButton.js"
import { ButtonSize } from "./ButtonSize.js"
import { px, size } from "../size.js"
import { component_size, px, size } from "../size.js"
import { InfoIcon } from "./InfoIcon.js"
assertMainOrNode()
@ -161,7 +161,7 @@ export class Table implements Component<TableAttrs> {
"td",
{
style: {
width: px(size.button_height_compact),
width: px(component_size.button_height_compact),
},
},
lineAttrs.actionButtonAttrs ? m(IconButton, lineAttrs.actionButtonAttrs) : [],

View file

@ -355,7 +355,7 @@ export class WizardPagingButton {
isPreviousPage
? m(Icon, {
icon: Icons.Checkmark,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: theme.surface,
},

View file

@ -15,7 +15,6 @@ export default function renderSwitchMonthArrowIcon(forward: boolean, size: numbe
icon: forward ? Icons.ArrowForward : BootIcons.Back,
container: "div",
class: "center-h",
size: IconSize.Normal,
style: {
fill: theme.on_surface,
},

View file

@ -4,7 +4,7 @@ import { lang, MaybeTranslation } from "../../../misc/LanguageViewModel.js"
import { AllIcons, Icon } from "../Icon.js"
import { theme } from "../../theme.js"
import { styles } from "../../styles.js"
import { px, size } from "../../size.js"
import { component_size, px, size } from "../../size.js"
export interface BubbleButtonAttrs {
label: MaybeTranslation
@ -14,7 +14,7 @@ export interface BubbleButtonAttrs {
}
export function bubbleButtonHeight(): number {
return usingMobileBubbleButton() ? size.button_height : size.button_height_bubble
return usingMobileBubbleButton() ? component_size.button_height : component_size.button_height_bubble
}
export function usingMobileBubbleButton() {

View file

@ -46,10 +46,10 @@ export class RowButton implements Component<RowButtonAttrs> {
container: "div",
class: "mr-button",
style: { fill: color },
size: IconSize.Medium,
size: IconSize.PX24,
})
: attrs.icon === "none"
? m(".icon-large.mr-button")
? m(".icon-24.mr-button")
: null,
class: "flex items-center state-bg button-content plr-button " + attrs.class,
style: {

View file

@ -45,7 +45,7 @@ export class SectionButton implements Component<SectionButtonAttrs> {
icon: leftIcon.icon,
style: { fill: leftIcon.fill ?? getColors(ButtonColor.Content).button },
title: lang.get(leftIcon.title),
size: IconSize.Medium,
size: IconSize.PX24,
}),
injectionLeft == null ? null : injectionLeft,
])
@ -57,13 +57,13 @@ export class SectionButton implements Component<SectionButtonAttrs> {
icon: Icons.ArrowForward,
style: { fill: getColors(ButtonColor.Content).button },
title: lang.get("next_action"),
size: IconSize.Medium,
size: IconSize.PX24,
})
: m(Icon, {
icon: rightIcon.icon,
style: { fill: rightIcon.fill ?? getColors(ButtonColor.Content).button },
title: lang.get(rightIcon.title),
size: IconSize.Medium,
size: IconSize.PX24,
}),
])

View file

@ -24,7 +24,7 @@ export class ToggleButton implements Component<ToggleButtonAttrs> {
icon: attrs.icon,
container: "div",
class: "center-h",
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: getColors(attrs.colors ?? ButtonColor.Content).button,
},

View file

@ -1,7 +1,7 @@
import m, { Component, Vnode } from "mithril"
import { lang, TranslationKey } from "../../misc/LanguageViewModel"
import { BaseButton } from "../base/buttons/BaseButton"
import { px, size } from "../size"
import { component_size, px, size } from "../size"
import { theme } from "../theme"
// The subActionText is optional, if null is passed it will not display the second Option
@ -26,7 +26,7 @@ export class ContentWithOptionsDialog implements Component<ContentWithOptionsDia
onclick: attrs.mainActionClick,
class: "full-width border-radius-m center b flash accent-bg button-content",
style: {
height: px(size.button_height + size.vpad_xs * 1.5),
height: px(component_size.button_height + size.vpad_xs * 1.5),
},
}),
@ -38,7 +38,7 @@ export class ContentWithOptionsDialog implements Component<ContentWithOptionsDia
class: "full-width border-radius-m center b flash",
style: {
border: `2px solid ${theme.primary}`,
height: px(size.button_height + size.vpad_xs * 1.5),
height: px(component_size.button_height + size.vpad_xs * 1.5),
color: theme.primary,
},
})

View file

@ -1,7 +1,7 @@
import m, { Component, Vnode } from "mithril"
import { lang, TranslationKey } from "../../misc/LanguageViewModel"
import { BaseButton } from "../base/buttons/BaseButton"
import { px, size } from "../size"
import { component_size, px, size } from "../size"
import { theme } from "../theme"
// The subActionText is optional, if null is passed it will not display the second Option
@ -48,7 +48,7 @@ export class ImageWithOptionsDialog implements Component<ImageWithOptionsDialogA
onclick: attrs.mainActionClick,
class: "full-width border-radius-small center b flash accent-bg button-content",
style: {
height: px(size.button_height + size.vpad_xs * 1.5),
height: px(component_size.button_height + size.vpad_xs * 1.5),
},
}),
@ -60,7 +60,7 @@ export class ImageWithOptionsDialog implements Component<ImageWithOptionsDialogA
class: "full-width border-radius-small center b flash",
style: {
border: `2px solid ${theme.primary}`,
height: px(size.button_height + size.vpad_xs * 1.5),
height: px(component_size.button_height + size.vpad_xs * 1.5),
color: theme.primary,
},
})

View file

@ -1,5 +1,5 @@
import { styles } from "./styles"
import { px, size } from "./size"
import { px, size, component_size } from "./size"
import { client } from "../misc/ClientDetector"
import { lang } from "../misc/LanguageViewModel"
import { noselect, position_absolute } from "./mixins"
@ -525,7 +525,7 @@ styles.registerStyle("main", () => {
"padding-bottom": px(size.vpad_ml),
},
".pb-floating": {
"padding-bottom": px(size.button_floating_size + size.hpad_large),
"padding-bottom": px(component_size.button_floating_size + size.hpad_large),
},
".pb-hpad-button": {
"padding-bottom": px(size.hpad_button),
@ -709,7 +709,7 @@ styles.registerStyle("main", () => {
width: "auto",
},
".min-width-l": {
"min-width": px(size.icon_segment_control_button_width),
"min-width": px(component_size.icon_segment_control_button_width),
},
".min-width-0": {
"min-width": 0,
@ -1040,22 +1040,22 @@ styles.registerStyle("main", () => {
color: theme.primary,
},
".button-height": {
height: px(size.button_height),
height: px(component_size.button_height),
},
".button-min-height": {
"min-height": px(size.button_height),
"min-height": px(component_size.button_height),
},
".button-min-width": {
"min-width": px(size.button_height),
"min-width": px(component_size.button_height),
},
".button-width-fixed": {
width: px(size.button_height),
width: px(component_size.button_height),
},
".large-button-height": {
height: px(size.button_floating_size),
height: px(component_size.button_floating_size),
},
".large-button-width": {
width: px(size.button_floating_size),
width: px(component_size.button_floating_size),
},
".notification-min-width": {
"min-width": px(400),
@ -1308,46 +1308,47 @@ styles.registerStyle("main", () => {
transition: "flex 200ms linear",
},
".border-radius": {
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
},
".border-radius-top": {
"border-top-left-radius": px(size.border_radius),
"border-top-right-radius": px(size.border_radius),
"border-top-left-radius": px(size.radius_8),
"border-top-right-radius": px(size.radius_8),
},
".border-radius-top-big": {
"border-top-left-radius": px(size.border_radius_larger),
"border-top-right-radius": px(size.border_radius_larger),
"border-top-left-radius": px(size.radius_12),
"border-top-right-radius": px(size.radius_12),
},
".border-radius-top-left-big": {
"border-top-left-radius": px(size.border_radius_larger),
"border-top-left-radius": px(size.radius_12),
},
".border-radius-top-right-big": {
"border-top-right-radius": px(size.border_radius_larger),
"border-top-right-radius": px(size.radius_12),
},
".border-radius-bottom": {
"border-bottom-left-radius": px(size.border_radius),
"border-bottom-right-radius": px(size.border_radius),
"border-bottom-left-radius": px(size.radius_8),
"border-bottom-right-radius": px(size.radius_8),
},
".border-radius-small": {
"border-radius": px(size.border_radius_small),
"border-radius": px(size.radius_4),
},
".border-radius-big": {
"border-radius": px(size.border_radius_larger),
"border-radius": px(size.radius_12),
},
// FIXME: combine to border-radius or use larger radius token
".border-radius-m": {
"border-radius": px(size.border_radius_medium),
"border-radius": px(size.radius_8),
},
".border-radius-top-left-m": {
"border-top-left-radius": px(size.border_radius_medium),
"border-top-left-radius": px(size.radius_8),
},
".border-radius-bottom-left-m": {
"border-bottom-left-radius": px(size.border_radius_medium),
"border-bottom-left-radius": px(size.radius_8),
},
".border-radius-bottom-right-m": {
"border-bottom-right-radius": px(size.border_radius_medium),
"border-bottom-right-radius": px(size.radius_8),
},
".border-radius-top-right-m": {
"border-top-right-radius": px(size.border_radius_medium),
"border-top-right-radius": px(size.radius_8),
},
".settings-item": {
border: 0,
@ -1391,7 +1392,7 @@ styles.registerStyle("main", () => {
width: px(size.icon_16),
},
// a bit cursed solution to make the visible icon not too huge relative to the tiny "close" icon that we have but also to keep the size consistent
// with icon-large so that the text field doesn't jump around
// with icon-24 so that the text field doesn't jump around
".icon-progress-search": {
height: `${px(20)} !important`,
width: `${px(20)} !important`,
@ -1430,43 +1431,43 @@ styles.registerStyle("main", () => {
height: px(size.icon_12),
width: px(size.icon_12),
},
".icon-large": {
".icon-24": {
height: px(size.icon_24),
width: px(size.icon_24),
},
".icon-medium-large": {
".icon-20": {
height: px(size.icon_20),
width: px(size.icon_20),
},
".icon-medium-large > svg": {
".icon-20 > svg": {
height: px(size.icon_20),
width: px(size.icon_20),
},
".icon-large > svg": {
".icon-24 > svg": {
height: px(size.icon_24),
width: px(size.icon_24),
},
".icon-xl": {
".icon-32": {
height: px(size.icon_32),
width: px(size.icon_32),
},
".icon-xl > svg": {
".icon-32 > svg": {
height: px(size.icon_32),
width: px(size.icon_32),
},
".icon-xxl": {
".icon-64": {
height: px(size.icon_64),
width: px(size.icon_64),
},
".icon-xxl > svg": {
".icon-64 > svg": {
height: px(size.icon_64),
width: px(size.icon_64),
},
".icon-message-box": {
".icon-80": {
height: px(size.icon_80),
width: px(size.icon_80),
},
".icon-message-box > svg": {
".icon-80 > svg": {
height: px(size.icon_80),
width: px(size.icon_80),
},
@ -1480,20 +1481,20 @@ styles.registerStyle("main", () => {
},
".icon-button": {
"border-radius": "25%",
width: px(size.button_height),
height: px(size.button_height),
"max-width": px(size.button_height),
"max-height": px(size.button_height),
width: px(component_size.button_height),
height: px(component_size.button_height),
"max-width": px(component_size.button_height),
"max-height": px(component_size.button_height),
},
".center-h": {
margin: "0 auto",
},
".toggle-button": {
"border-radius": "25%",
width: px(size.button_height),
height: px(size.button_height),
"max-width": px(size.button_height),
"max-height": px(size.button_height),
width: px(component_size.button_height),
height: px(component_size.button_height),
"max-width": px(component_size.button_height),
"max-height": px(component_size.button_height),
},
".wizard-next-button": {
"margin-top": "auto",
@ -1536,14 +1537,14 @@ styles.registerStyle("main", () => {
transition: `border-top-color ${DefaultAnimationTime}ms ease-out`,
},
".compact": {
width: `${size.button_height_compact}px !important`,
height: `${size.button_height_compact}px !important`,
width: `${component_size.button_height_compact}px !important`,
height: `${component_size.button_height_compact}px !important`,
},
".large": {
width: `${size.button_floating_size}px`,
height: `${size.button_floating_size}px`,
"max-width": `${size.button_floating_size}px`,
"max-height": `${size.button_floating_size}px`,
width: `${component_size.button_floating_size}px`,
height: `${component_size.button_floating_size}px`,
"max-width": `${component_size.button_floating_size}px`,
"max-height": `${component_size.button_floating_size}px`,
},
// state-bg is a simulation of a "state layer" from Material but without an additional layer
// We don't exactly follow transparency for it because we combine transparency with light grey color which works well on both light and dark themes
@ -1653,7 +1654,7 @@ styles.registerStyle("main", () => {
},
// header
".header-nav": {
height: px(size.navbar_height),
height: px(component_size.navbar_height),
"background-color": theme.surface_container,
"z-index": 2,
},
@ -1664,7 +1665,7 @@ styles.registerStyle("main", () => {
*/
"box-sizing": "border-box",
"border-top": `1px solid ${theme.outline_variant}`,
height: `calc(${size.bottom_nav_bar}px + env(safe-area-inset-bottom))`,
height: `calc(${component_size.bottom_nav_bar}px + env(safe-area-inset-bottom))`,
background: theme.surface,
"padding-bottom": "env(safe-area-inset-bottom)",
"z-index": 2,
@ -1675,14 +1676,14 @@ styles.registerStyle("main", () => {
"padding-top": px(size.vpad),
},
".logo-circle": {
width: px(size.button_icon_bg_size),
height: px(size.button_icon_bg_size),
width: px(component_size.button_icon_bg_size),
height: px(component_size.button_icon_bg_size),
"border-radius": "50%",
overflow: "hidden",
},
".dot": {
width: px(size.dot_size),
height: px(size.dot_size),
width: px(component_size.dot_size),
height: px(component_size.dot_size),
"border-radius": "50%",
overflow: "hidden",
"margin-top": px(6),
@ -1691,14 +1692,14 @@ styles.registerStyle("main", () => {
position: "relative",
},
".logo-text": {
height: px(size.header_logo_height),
height: px(component_size.header_logo_height),
width: px(128),
},
".logo-height": {
height: px(size.header_logo_height),
height: px(component_size.header_logo_height),
},
".logo-height > svg, .logo-height > img": {
height: px(size.header_logo_height),
height: px(component_size.header_logo_height),
},
".custom-logo": {
width: px(200),
@ -1731,10 +1732,10 @@ styles.registerStyle("main", () => {
},
".dialog-header": {
"border-bottom": `1px solid ${theme.outline_variant}`,
height: px(size.button_height + 1),
height: px(component_size.button_height + 1),
},
".dialog-header-line-height": {
"line-height": px(size.button_height),
"line-height": px(component_size.button_height),
},
".dialog-progress": {
"text-align": "center",
@ -1745,7 +1746,7 @@ styles.registerStyle("main", () => {
"max-width": "100%",
height: "auto",
},
".dialog-container": position_absolute(size.button_height + 1, 0, 0, 0),
".dialog-container": position_absolute(component_size.button_height + 1, 0, 0, 0),
".dialog-contentButtonsBottom": {
padding: `0 ${px(size.hpad_large)} ${px(size.vpad)} ${px(size.hpad_large)}`,
},
@ -1789,7 +1790,7 @@ styles.registerStyle("main", () => {
position: "relative",
},
".template-list-row": {
"border-left": px(size.border_selection) + " solid transparent",
"border-left": px(size.radius_4) + " solid transparent",
"align-items": "center",
position: "relative",
},
@ -1813,8 +1814,8 @@ styles.registerStyle("main", () => {
color: `${theme.primary}`,
},
".expander": {
height: px(size.button_height),
"min-width": px(size.button_height),
height: px(component_size.button_height),
"min-width": px(component_size.button_height),
},
// mail view editor
".mail-viewer-firstLine": {
@ -1856,7 +1857,7 @@ styles.registerStyle("main", () => {
position: "absolute",
left: 0,
right: 0,
height: px(size.list_row_height),
height: px(component_size.list_row_height),
},
".odd-row": {
"background-color": theme.surface,
@ -1948,7 +1949,7 @@ styles.registerStyle("main", () => {
"border-color": theme.outline,
"padding-bottom": "1px",
"z-index": 1,
"border-radius": `${size.border_radius}px ${size.border_radius}px 0 0`,
"border-radius": `${size.radius_8}px ${size.radius_8}px 0 0`,
color: theme.on_surface,
},
".dropdown-bar:focus": {
@ -1958,7 +1959,7 @@ styles.registerStyle("main", () => {
"padding-bottom": "0px",
},
".dropdown-button": {
height: px(size.button_height),
height: px(component_size.button_height),
"padding-left": px(size.vpad),
"padding-right": px(size.vpad),
},
@ -1990,33 +1991,33 @@ styles.registerStyle("main", () => {
}
: {},
".button-icon": {
width: px(size.button_icon_bg_size),
height: px(size.button_icon_bg_size),
"border-radius": px(size.button_icon_bg_size),
"min-width": px(size.button_icon_bg_size),
width: px(component_size.button_icon_bg_size),
height: px(component_size.button_icon_bg_size),
"border-radius": px(component_size.button_icon_bg_size),
"min-width": px(component_size.button_icon_bg_size),
},
".login": {
width: "100%",
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
},
".small-login-button": {
width: "260px",
},
".button-content": {
height: px(size.button_height),
"min-width": px(size.button_height),
height: px(component_size.button_height),
"min-width": px(component_size.button_height),
},
".text-bubble": {
"padding-top": px(size.text_bubble_tpad),
},
".bubble": {
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
"background-color": theme.surface_container_high,
color: theme.on_surface,
},
".keyword-bubble": {
"max-width": "300px",
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
"margin-bottom": px(size.vpad_small / 2),
"margin-right": px(size.vpad_small / 2),
"background-color": theme.surface_container_high,
@ -2025,7 +2026,7 @@ styles.registerStyle("main", () => {
},
".keyword-bubble-no-padding": {
"max-width": "300px",
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
margin: px(size.vpad_small / 2),
"background-color": theme.surface_container_high,
color: theme.on_surface,
@ -2040,8 +2041,8 @@ styles.registerStyle("main", () => {
},
".segmentControl": {
// same border as for bubble buttons
"border-top": `${px((size.button_height - size.button_height_bubble) / 2)} solid transparent`,
"border-bottom": `${px((size.button_height - size.button_height_bubble) / 2)} solid transparent`,
"border-top": `${px((component_size.button_height - component_size.button_height_bubble) / 2)} solid transparent`,
"border-bottom": `${px((component_size.button_height - component_size.button_height_bubble) / 2)} solid transparent`,
},
".segmentControl-border": {
border: `1px solid ${theme.outline}`,
@ -2058,25 +2059,25 @@ styles.registerStyle("main", () => {
background: "transparent",
},
".segmentControlItem:last-child": {
"border-bottom-right-radius": px(size.border_radius_small),
"border-top-right-radius": px(size.border_radius_small),
"border-bottom-right-radius": px(size.radius_4),
"border-top-right-radius": px(size.radius_4),
},
".segmentControlItem:first-child": {
"border-bottom-left-radius": px(size.border_radius_small),
"border-top-left-radius": px(size.border_radius_small),
"border-bottom-left-radius": px(size.radius_4),
"border-top-left-radius": px(size.radius_4),
},
// IconSegmentControl
".icon-segment-control": {
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
},
".icon-segment-control-item": {
// Make thin border between items via border-right
"border-top": `1px solid ${theme.outline_variant}`,
"border-bottom": `1px solid ${theme.outline_variant}`,
"border-right": `0.5px solid ${theme.outline_variant}`,
width: px(size.icon_segment_control_button_width),
height: px(size.icon_segment_control_button_height),
width: px(component_size.icon_segment_control_button_width),
height: px(component_size.icon_segment_control_button_height),
cursor: "pointer",
background: "transparent",
},
@ -2086,13 +2087,13 @@ styles.registerStyle("main", () => {
"transition-duration": ".3s",
},
".icon-segment-control-item:first-child": {
"border-bottom-left-radius": px(size.border_radius),
"border-top-left-radius": px(size.border_radius),
"border-bottom-left-radius": px(size.radius_8),
"border-top-left-radius": px(size.radius_8),
"border-left": `1px solid ${theme.outline_variant}`,
},
".icon-segment-control-item:last-child": {
"border-bottom-right-radius": px(size.border_radius),
"border-top-right-radius": px(size.border_radius),
"border-bottom-right-radius": px(size.radius_8),
"border-top-right-radius": px(size.radius_8),
"border-right": `1px solid ${theme.outline_variant}`,
},
".payment-logo": {
@ -2365,9 +2366,9 @@ styles.registerStyle("main", () => {
// reset browser style
margin: "0",
display: "block",
width: px(size.checkbox_size),
height: px(size.checkbox_size),
border: `${px(size.checkbox_border_size)} solid ${theme.outline}`,
width: px(component_size.checkbox_size),
height: px(component_size.checkbox_size),
border: `${px(component_size.checkbox_border_size)} solid ${theme.outline}`,
"border-radius": "3px",
position: "relative",
transition: `border ${DefaultAnimationTime}ms cubic-bezier(.4,.0,.23,1)`,
@ -2408,7 +2409,7 @@ styles.registerStyle("main", () => {
// position relative to the inner size of checkbox (inside the border)
top: "-10px",
left: "-10px",
"border-radius": px(size.border_radius),
"border-radius": px(size.radius_8),
// position is relate to padding and we animate padding so to keep the checkbox in place we also animate position so it looks like it doesn't move
transition: `all ${DefaultAnimationTime}ms cubic-bezier(.4,.0,.23,1)`,
},
@ -2749,7 +2750,7 @@ styles.registerStyle("main", () => {
bottom: 0,
},
".fixed-bottom-right": {
bottom: px(size.hpad_large_mobile + size.bottom_nav_bar),
bottom: px(size.hpad_large_mobile + component_size.bottom_nav_bar),
right: px(size.hpad_large_mobile),
},
".custom-logo": {
@ -2967,7 +2968,7 @@ styles.registerStyle("main", () => {
".tutaui-card-container": {
"box-sizing": "border-box",
"background-color": theme.surface,
"border-radius": px(size.border_radius_medium),
"border-radius": px(size.radius_8),
padding: px(size.vpad_small),
height: "fit-content",
},
@ -2983,7 +2984,7 @@ styles.registerStyle("main", () => {
"box-sizing": "border-box",
"background-color": "transparent",
border: "none",
"border-radius": px(size.border_radius_medium),
"border-radius": px(size.radius_8),
color: theme.on_surface,
width: "100%",
padding: px(size.vpad_small),
@ -3073,8 +3074,8 @@ styles.registerStyle("main", () => {
},
".tutaui-button-outline": {
border: "1px solid",
"border-radius": px(size.border_radius_medium),
padding: px(size.border_radius_medium),
"border-radius": px(size.radius_8),
padding: px(size.radius_8),
"text-align": "center",
},
".unstyled-list": {
@ -3130,7 +3131,7 @@ styles.registerStyle("main", () => {
},
".outlined": {
border: `2px solid ${theme.outline}`,
"border-radius": px(size.border_radius_medium),
"border-radius": px(size.radius_8),
},
".capitalize": {
"text-transform": "capitalize",

View file

@ -40,7 +40,7 @@ export class DrawerMenu implements Component<DrawerMenuAttrs> {
...landmarkAttrs(AriaLandmarks.Contentinfo, "drawer menu"),
style: {
"padding-left": getSafeAreaInsetLeft(),
"border-top-right-radius": styles.isDesktopLayout() ? px(size.border_radius_larger) : "",
"border-top-right-radius": styles.isDesktopLayout() ? px(size.radius_12) : "",
},
},
[

View file

@ -5,11 +5,11 @@ export const size = {
/*
Base & core size
Use core sizes whenever it's possible.
It reduces the cognitive load on users, and enable us to make better and faster decisions with fewer options.
It reduces the cognitive load on users, and enable developers to make better and faster decisions with fewer options.
Increments of 4 (base) are allowed for design flexibility, but try to use the core sizes first.
See also: https://www.figma.com/design/AGqWHYG9dYRMCFcW5sKWhp/Switch---Tuta-Design-System?node-id=19-4
*/
base: 4,
base_4: 4,
core_8: 8,
core_16: 16,
core_24: 24,
@ -26,7 +26,7 @@ export const size = {
// Spacings
get spacing_4() {
return this.base
return this.base_4
},
get spacing_8() {
return this.core_8
@ -49,13 +49,13 @@ export const size = {
// Icons
get icon_12() {
return this.core_8 + this.base
return this.core_8 + this.base_4
},
get icon_16() {
return this.core_16
},
get icon_20() {
return this.core_16 + this.base
return this.core_16 + this.base_4
},
get icon_24() {
return this.core_24
@ -72,14 +72,18 @@ export const size = {
// Radii
get radius_4() {
return this.base
return this.base_4
},
get radius_8() {
return this.core_8
},
get radius_12() {
return this.core_8 + this.base_4
},
get radius_16() {
return this.core_16
},
// FIXME: update to "spacing_<px>" tokens
hpad_small: 5,
hpad: 10,
@ -100,17 +104,54 @@ export const size = {
vpad_xl: 48,
vpad_xxl: 64,
text_bubble_tpad: 20,
// FIXME: update to "radius_<px>" tokens
border_radius_small: 3,
border_radius: 6,
border_radius_medium: 8,
border_radius_larger: 9,
border_radius_large: 12,
border_selection: 4,
font_size_base: 16,
font_size_smaller: 14,
font_size_small: 12,
// FIXME: Create component_size object
line_height: 1.428571429,
// 20/14,
line_height_m: 1.6,
line_height_l: 1.8,
// FIXME: Create a layout_size object
get calendar_line_height(): number {
return this.font_size_small + 6
},
get calendar_hour_height(): number {
return (this.calendar_line_height + 2 * this.calendar_event_border + this.calendar_day_event_padding) * 4
},
calendar_days_header_height: 25,
calendar_hour_width: 80,
calendar_hour_width_mobile: 30,
calendar_event_margin: 6,
calendar_event_margin_mobile: 2,
calendar_event_border: 1,
calendar_day_event_padding: 2,
drawer_menu_width: 44,
column_width_s_desktop: 135,
column_width_s_mobile: 70,
first_col_min_width: 240,
first_col_max_width: 300,
second_col_min_width: 300,
second_col_max_width: 350,
third_col_min_width: 600,
third_col_max_width: 2400,
only_show_in_single_column_min_max_width: 10000, // viewport >= every mobile device viewport
get desktop_layout_width(): number {
return this.first_col_min_width + this.second_col_min_width + this.third_col_min_width
},
get two_column_layout_width(): number {
return this.second_col_min_width + this.third_col_min_width
},
column_resize_element_width: 5,
}
export const component_size = {
button_height: 44,
button_height_accent: 40,
button_height_bubble: 30,
@ -130,19 +171,14 @@ export const size = {
list_row_height: 68,
column_width_s_desktop: 135,
column_width_s_mobile: 70,
line_height: 1.428571429,
// 20/14,
line_height_m: 1.6,
line_height_l: 1.8,
get calendar_line_height(): number {
return this.font_size_small + 6
return size.font_size_small + 6
},
get calendar_hour_height(): number {
return (this.calendar_line_height + 2 * this.calendar_event_border + this.calendar_day_event_padding) * 4
},
calendar_days_header_height: 25,
calendar_hour_width: 80,
calendar_hour_width_mobile: 30,
@ -151,32 +187,14 @@ export const size = {
calendar_event_border: 1,
calendar_day_event_padding: 2,
drawer_menu_width: 44,
// FIXME: Create a layout_size object
first_col_min_width: 240,
first_col_max_width: 300,
second_col_min_width: 300,
second_col_max_width: 350,
third_col_min_width: 600,
third_col_max_width: 2400,
only_show_in_single_column_min_max_width: 10000, // viewport >= every mobile device viewport
get desktop_layout_width(): number {
return this.first_col_min_width + this.second_col_min_width + this.third_col_min_width
},
get two_column_layout_width(): number {
return this.second_col_min_width + this.third_col_min_width
},
dot_size: 7,
checkbox_size: 14,
checkbox_border_size: 2,
get checkbox_helper_text_margin(): number {
return this.checkbox_size + this.checkbox_border_size + this.hpad_small
return this.checkbox_size + this.checkbox_border_size + size.hpad_small
},
column_resize_element_width: 5,
}
export const inputLineHeight: number = size.font_size_base + 8
export function px(value: number): string {

View file

@ -105,7 +105,7 @@ export class SecondFactorAuthView implements Component<SecondFactorViewAttrs> {
".mr-s",
m(Icon, {
icon: Icons.Cancel,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: theme.primary,
},

View file

@ -50,7 +50,7 @@ export function showRequestPasswordDialog(props: {
])
: m(Icon, {
icon: BootIcons.Progress,
class: "icon-xl icon-progress block mt mb",
class: "icon-32 icon-progress block mt mb",
style: {
marginLeft: "auto",
marginRight: "auto",

View file

@ -1,6 +1,6 @@
import m, { Children } from "mithril"
import { NotFoundError } from "../api/common/error/RestError.js"
import { size } from "../gui/size.js"
import { component_size, size } from "../gui/size.js"
import type { GroupInfo } from "../api/entities/sys/TypeRefs.js"
import { GroupInfoTypeRef, GroupMemberTypeRef } from "../api/entities/sys/TypeRefs.js"
import { contains, LazyLoaded, noOp } from "@tutao/tutanota-utils"
@ -48,7 +48,7 @@ export class UserListView implements UpdatableSettingsViewer {
m.render(dom, row.render())
return row
},
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
swipe: null,
multiselectionAllowed: MultiselectMode.Disabled,
}

View file

@ -45,7 +45,7 @@ export class FingerprintRow implements Component<FingerprintRowAttrs> {
m(".flex.items-center.selectable.pl-vpad-s.mb-s.gap-vpad-xs", [
m(Icon, {
icon: Icons.Shield,
size: IconSize.Large,
size: IconSize.PX20,
style: { fill: theme.success },
}),
m(".text-break.b.selectable", mailAddress),

View file

@ -64,7 +64,7 @@ export class FingerprintMismatchInfoPage implements Component<VerificationErrorI
class: "flex-center row center-vertically",
icon: m(Icon, {
icon: Icons.Trash,
size: IconSize.Medium,
size: IconSize.PX24,
class: "mr-s flex-center",
style: {
fill: theme.on_primary,

View file

@ -51,7 +51,7 @@ export class RecipientKeyVerificationRecoveryInfoPage implements Component<Verif
onclick: async () => vnode.attrs.goToRejectPage(),
icon: m(Icon, {
icon: Icons.XCheckmark,
size: IconSize.Large,
size: IconSize.PX20,
class: "mr-s flex-center",
}),
}),

View file

@ -59,7 +59,7 @@ export class SenderKeyVerificationRecoveryInfoPage implements Component<Verifica
onclick: async () => vnode.attrs.goToRejectPage(),
icon: m(Icon, {
icon: Icons.XCheckmark,
size: IconSize.Large,
size: IconSize.PX20,
class: "mr-s flex-center",
style: {
fill: theme.on_primary,

View file

@ -98,7 +98,7 @@ export class VerificationByManualInputPage implements Component<VerificationByTe
},
icon: m(Icon, {
icon: Icons.XCheckmark,
size: IconSize.Large,
size: IconSize.PX20,
class: "mr-s flex-center",
}),
}),
@ -110,7 +110,7 @@ export class VerificationByManualInputPage implements Component<VerificationByTe
},
icon: m(Icon, {
icon: Icons.XCross,
size: IconSize.Large,
size: IconSize.PX20,
class: "mr-s flex-center",
style: {
fill: theme.surface,

View file

@ -202,7 +202,7 @@ export class SecondFactorEditDialog {
case VerificationStatus.Success:
return m(Icon, {
icon: Icons.Checkmark,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: theme.primary,
},
@ -211,7 +211,7 @@ export class SecondFactorEditDialog {
case VerificationStatus.Failed:
return m(Icon, {
icon: Icons.Cancel,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: theme.primary,
},

View file

@ -1,5 +1,5 @@
import m, { Children, Component } from "mithril"
import { px, size } from "../../gui/size"
import { component_size, px, size } from "../../gui/size"
import { Button, ButtonType } from "../../gui/base/Button.js"
import { createMail, createMailAddress, Mail } from "../../api/entities/tutanota/TypeRefs.js"
import { MailRow } from "../../../mail-app/mail/view/MailRow"
@ -124,7 +124,7 @@ export class CustomColorEditorPreview implements Component {
{
style: {
width: px(size.second_col_max_width),
height: px(size.list_row_height * 2),
height: px(component_size.list_row_height * 2),
},
},
[
@ -146,7 +146,7 @@ export class CustomColorEditorPreview implements Component {
requestAnimationFrame(() => this._mailRow2.update(mail2, true, false))
},
style: {
top: px(size.list_row_height),
top: px(component_size.list_row_height),
},
},
this._mailRow2.render(),

View file

@ -1,5 +1,5 @@
import m, { Children, Component, Vnode } from "mithril"
import { size } from "../../gui/size"
import { component_size, size } from "../../gui/size"
import { getCapabilityText } from "../GroupUtils"
import { downcast } from "@tutao/tutanota-utils"
import { showGroupInvitationDialog } from "./ReceivedGroupInvitationDialog.js"
@ -25,7 +25,7 @@ export class GroupInvitationFolderRow implements Component<GroupInvitationFolder
style: {
// It's kinda hard to tell this element to not eat up all the row and truncate text instead because it
// is vertical flex. With this it will stop at 80% of what it could be and that's enough for the button.
"max-width": `calc(100% - ${size.button_height}px)`,
"max-width": `calc(100% - ${component_size.button_height}px)`,
},
},
[

View file

@ -73,7 +73,7 @@ export function getActiveSubscriptionActionButtonReplacement(): () => Children {
".buyOptionBox.content-accent-fg.center-vertically.text-center",
{
style: {
"border-radius": px(size.border_radius_small),
"border-radius": px(size.radius_4),
},
},
lang.get("pricing.currentPlan_label"),

View file

View file

View file

@ -4,7 +4,7 @@ import { PaymentInterval, PriceAndConfigProvider } from "./utils/PriceUtils"
import { SelectedSubscriptionOptions } from "./FeatureListProvider"
import { lazy } from "@tutao/tutanota-utils"
import { AvailablePlanType, PlanType } from "../api/common/TutanotaConstants.js"
import { px, size } from "../gui/size.js"
import { component_size, px, size } from "../gui/size.js"
import { LoginButton, LoginButtonAttrs, LoginButtonType } from "../gui/base/buttons/LoginButton.js"
import Stream from "mithril/stream"
import stream from "mithril/stream"
@ -151,7 +151,7 @@ export class PlanSelector implements Component<PlanSelectorAttr> {
"#plan-selector.flex.flex-column.gap-vpad-l",
{
style: this.shouldFixButtonPos() && {
"padding-bottom": px(size.button_floating_size + size.vpad),
"padding-bottom": px(component_size.button_floating_size + size.vpad),
},
lang: lang.code,
},
@ -180,7 +180,7 @@ export class PlanSelector implements Component<PlanSelectorAttr> {
{
style: this.shouldFixButtonPos() && {
position: "fixed",
height: px(size.button_floating_size + size.vpad_xsm * 2),
height: px(component_size.button_floating_size + size.vpad_xsm * 2),
bottom: 0,
left: 0,
right: 0,
@ -222,7 +222,7 @@ export class PlanSelector implements Component<PlanSelectorAttr> {
const contentHeight = parseInt(getComputedStyle(planSelectorEl).height)
const containerHeight = parseInt(getComputedStyle(containerEl).height)
this.shouldFixButtonPos(contentHeight + size.button_floating_size > containerHeight)
this.shouldFixButtonPos(contentHeight + component_size.button_floating_size > containerHeight)
}
}
}

View file

@ -366,7 +366,7 @@ export function getPrivateBusinessSwitchButton(businessUse: Stream<boolean>, ava
? null
: m(Icon, {
icon: isBusiness ? BootIcons.User : Icons.Business,
size: IconSize.Large,
size: IconSize.PX20,
class: "mr-xsm",
style: {
fill: theme.primary,

View file

@ -131,7 +131,7 @@ class GiftCardPurchaseView implements Component<GiftCardPurchaseViewAttrs> {
Array(Math.pow(2, index)).fill(
m(Icon, {
icon: Icons.Gift,
size: IconSize.Medium,
size: IconSize.PX24,
}),
),
),

View file

@ -180,7 +180,6 @@ export class ContactSupportPage implements Component<Props> {
paddingInline: px((size.icon_24 - size.icon_16) / 2),
},
title: lang.get("remove_action"),
size: IconSize.Normal,
}),
),
),

View file

@ -19,7 +19,7 @@ import {
} from "../../common/api/entities/tutanota/TypeRefs.js"
import m from "mithril"
import { List, ListAttrs, ListLoadingState, MultiselectMode, RenderConfig } from "../../common/gui/base/List.js"
import { size } from "../../common/gui/size.js"
import { component_size, size } from "../../common/gui/size.js"
import { UserError } from "../../common/api/main/UserError.js"
import { DialogHeaderBar, DialogHeaderBarAttrs } from "../../common/gui/base/DialogHeaderBar.js"
import { ButtonType } from "../../common/gui/base/Button.js"
@ -256,7 +256,7 @@ export function showContactImportDialog(contacts: Contact[], okAction: (dialog:
const viewModel: ContactImportDialogViewModel = new ContactImportDialogViewModel()
viewModel.selectContacts(contacts)
const renderConfig: RenderConfig<Contact, KindaContactRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Enabled,
swipe: null,
createElement: (dom) => {

View file

@ -5,7 +5,7 @@ import { ButtonType } from "../../common/gui/base/Button.js"
import { Dialog } from "../../common/gui/base/Dialog.js"
import m, { Children, Component, Vnode } from "mithril"
import { TextField } from "../../common/gui/base/TextField.js"
import { px, size } from "../../common/gui/size.js"
import { component_size, px, size } from "../../common/gui/size.js"
import { IconButton } from "../../common/gui/base/IconButton.js"
import { Icons } from "../../common/gui/base/icons/Icons.js"
import { MailRecipientsTextField } from "../../common/gui/MailRecipientsTextField.js"
@ -161,7 +161,7 @@ class ContactListEditor implements Component<ContactListEditorAttrs> {
".flex",
{
style: {
height: px(size.button_height),
height: px(component_size.button_height),
borderBottom: "1px transparent",
marginTop: px(size.vpad),
},

View file

@ -18,7 +18,7 @@ import {
SelectableRowSelectedSetter,
shouldAlwaysShowMultiselectCheckbox,
} from "../../../common/gui/SelectableRowContainer.js"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { shiftByForCheckbox, translateXHide, translateXShow } from "./ContactRow.js"
import { styles } from "../../../common/gui/styles.js"
@ -68,7 +68,7 @@ export class ContactListRecipientView implements Component<ContactListViewAttrs>
}
private readonly renderConfig: RenderConfig<ContactListEntry, RecipientRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Enabled,
swipe: null,
createElement: (dom) => {

View file

@ -1,6 +1,6 @@
import m, { Children, ClassComponent, Vnode } from "mithril"
import type { Contact } from "../../../common/api/entities/tutanota/TypeRefs.js"
import { size } from "../../../common/gui/size"
import { component_size, size } from "../../../common/gui/size"
import { ListColumnWrapper } from "../../../common/gui/ListColumnWrapper"
import { assertMainOrNode } from "../../../common/api/common/Env"
import { List, ListAttrs, MultiselectMode, RenderConfig, ViewHolder } from "../../../common/gui/base/List.js"
@ -62,7 +62,7 @@ export class ContactListView implements ClassComponent<ContactListViewAttrs> {
}
private readonly renderConfig: RenderConfig<Contact, KindaContactRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Enabled,
swipe: null,
createElement: (dom) => {

View file

@ -10,11 +10,11 @@ import {
import { getContactListName } from "../../../common/contactsFunctionality/ContactUtils.js"
import { NBSP, noOp } from "@tutao/tutanota-utils"
import m, { Children } from "mithril"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { setHTMLElementTextWithHighlighting, VirtualRow } from "../../../common/gui/base/ListUtils.js"
import { splitTextForHighlighting, SearchToken } from "../../../common/api/common/utils/QueryTokenUtils"
export const shiftByForCheckbox = px(size.checkbox_size + size.hpad)
export const shiftByForCheckbox = px(component_size.checkbox_size + size.hpad)
export const translateXShow = `translateX(${shiftByForCheckbox})`
export const translateXHide = "translateX(0)"

View file

@ -165,7 +165,7 @@ export class EventBannerImpl implements ClassComponent<EventBannerImplAttrs> {
container: "div",
class: "mr-xsm",
style: { fill: theme.on_surface },
size: IconSize.Medium,
size: IconSize.PX24,
}),
m("span.b.h5.text-ellipsis-multi-line.lh-s", event.summary),
]),
@ -196,7 +196,7 @@ export class EventBannerImpl implements ClassComponent<EventBannerImplAttrs> {
container: "div",
class: "mr-xsm mt-xxs",
style: { fill: theme.on_surface },
size: IconSize.Medium,
size: IconSize.PX24,
}),
m("span.b.h5", lang.get("timeOverview_title")),
]),
@ -209,7 +209,7 @@ export class EventBannerImpl implements ClassComponent<EventBannerImplAttrs> {
style: {
fill: hasConflict ? theme.warning : theme.success,
}, // TODO [colors] Use new material like colors tokens
size: IconSize.Medium,
size: IconSize.PX24,
}),
this.renderConflictInfoText(agenda.conflictCount, agenda.allDayEvents),
])

View file

@ -7,7 +7,7 @@ import { Button, ButtonType } from "../../../common/gui/base/Button.js"
import { elementIdPart, isSameId } from "../../../common/api/common/utils/EntityUtils.js"
import { CollapsedMailView } from "./CollapsedMailView.js"
import { MailViewerViewModel } from "./MailViewerViewModel.js"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { Keys } from "../../../common/api/common/TutanotaConstants.js"
import { keyManager, Shortcut } from "../../../common/misc/KeyManager.js"
import { styles } from "../../../common/gui/styles.js"
@ -146,7 +146,9 @@ export class ConversationViewer implements Component<ConversationViewerAttrs> {
// Having more room at the bottom allows the last email so it is (almost) always in the same place on the screen.
// We reduce space by 100 for the header of the viewer and a bit more
const height =
document.body.offsetHeight - (styles.isUsingBottomNavigation() ? size.navbar_height_mobile + size.bottom_nav_bar : size.navbar_height) - 300
document.body.offsetHeight -
(styles.isUsingBottomNavigation() ? component_size.navbar_height_mobile + component_size.bottom_nav_bar : component_size.navbar_height) -
300
return m(".mt-l.noprint", {
style: {
height: px(height),

View file

@ -7,7 +7,7 @@ import { alpha, AlphaEnum, AnimationPromise, animations, DefaultAnimationTime, o
import { getElevatedBackground, theme } from "../../../common/gui/theme.js"
import { INPUT } from "../../../common/gui/base/Dialog.js"
import { ease } from "../../../common/gui/animation/Easing.js"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { styles } from "../../../common/gui/styles.js"
import { LoginButton } from "../../../common/gui/base/buttons/LoginButton.js"
@ -60,16 +60,16 @@ export class EditFoldersDialog implements ModalComponent {
this.close()
}
this.usedBottomNavBefore = styles.isUsingBottomNavigation()
const marginTop = this.usedBottomNavBefore ? "env(safe-area-inset-top)" : px(size.navbar_height)
const marginTop = this.usedBottomNavBefore ? "env(safe-area-inset-top)" : px(component_size.navbar_height)
return m(
".flex.col",
{
style: {
width: px(size.first_col_max_width - size.button_height),
width: px(size.first_col_max_width - component_size.button_height),
height: `calc(100% - ${marginTop})`,
// for the header
marginTop,
marginLeft: px(size.button_height),
marginLeft: px(component_size.button_height),
},
onclick: (e: MouseEvent) => e.stopPropagation(),
// do not propagate clicks on the dialog as the Modal expects all propagated clicks to be clicks on the background

View file

@ -4,7 +4,7 @@ import { focusNext, focusPrevious, Shortcut } from "../../../common/misc/KeyMana
import { BaseButton, BaseButtonAttrs } from "../../../common/gui/base/buttons/BaseButton.js"
import { PosRect, showDropdown } from "../../../common/gui/base/Dropdown.js"
import { MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
import { size } from "../../../common/gui/size.js"
import { component_size, size } from "../../../common/gui/size.js"
import { AllIcons, Icon, IconSize } from "../../../common/gui/base/Icon.js"
import { Icons } from "../../../common/gui/base/icons/Icons.js"
import { theme } from "../../../common/gui/theme.js"
@ -91,7 +91,7 @@ export class LabelsPopup implements ModalComponent {
[
m(Icon, {
icon: this.iconForState(state),
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: getLabelColor(label.color),
opacity,
@ -185,7 +185,7 @@ export class LabelsPopup implements ModalComponent {
// restrict label height to showing maximum 6 labels to avoid overflow
const displayedLabels = Math.min(this.labels.length, 6)
const height = (displayedLabels + 1) * size.button_height + size.vpad_small * 2
const height = (displayedLabels + 1) * component_size.button_height + size.vpad_small * 2
showDropdown(this.origin, this.dom, height, this.width).then(() => {
const firstLabel = vnode.dom.getElementsByTagName("label-item").item(0)
if (firstLabel !== null) {

View file

@ -3,7 +3,7 @@ import type { NavButtonAttrs } from "../../../common/gui/base/NavButton.js"
import { isNavButtonSelected, NavButton } from "../../../common/gui/base/NavButton.js"
import { CounterBadge } from "../../../common/gui/base/CounterBadge"
import { theme } from "../../../common/gui/theme"
import { px, size } from "../../../common/gui/size"
import { component_size, px, size } from "../../../common/gui/size"
import { IconButton, IconButtonAttrs } from "../../../common/gui/base/IconButton.js"
import { Icon, IconSize } from "../../../common/gui/base/Icon.js"
import { Icons } from "../../../common/gui/base/icons/Icons.js"
@ -92,7 +92,7 @@ export class MailFolderRow implements Component<MailFolderRowAttrs> {
style: {
left: px(indentationMargin),
width: px(buttonWidth),
height: px(size.button_height),
height: px(component_size.button_height),
paddingLeft: px(paddingNeeded),
paddingRight: px(paddingNeeded),
// the zIndex is so the hierarchy lines never get drawn over the icon
@ -105,7 +105,7 @@ export class MailFolderRow implements Component<MailFolderRowAttrs> {
},
m(Icon, {
icon,
size: IconSize.Medium,
size: IconSize.PX24,
style: {
fill: isNavButtonSelected(button) ? theme.primary : theme.on_surface_variant,
},
@ -141,8 +141,8 @@ export class MailFolderRow implements Component<MailFolderRowAttrs> {
private renderHierarchyLine({ indentationLevel, numberOfPreviousRows, isLastSibling, onSelectedPath }: MailFolderRowAttrs, indentationMargin: number) {
const lineSize = 1
const border = `${lineSize}px solid ${theme.outline}`
const verticalOffsetInsideRow = size.button_height / 2 + 1
const verticalOffsetForParent = (size.button_height - size.icon_24) / 2
const verticalOffsetInsideRow = component_size.button_height / 2 + 1
const verticalOffsetForParent = (component_size.button_height - size.icon_24) / 2
const lengthOfHorizontalLine = size.hpad - 2
const leftOffset = indentationMargin
@ -156,8 +156,8 @@ export class MailFolderRow implements Component<MailFolderRowAttrs> {
borderBottomLeftRadius: "3px",
// there's some subtle difference between border we use here and the top for the other element and this +1 is to
// accommodate it
height: px(1 + verticalOffsetInsideRow + verticalOffsetForParent + numberOfPreviousRows * size.button_height),
top: px(-verticalOffsetForParent - numberOfPreviousRows * size.button_height),
height: px(1 + verticalOffsetInsideRow + verticalOffsetForParent + numberOfPreviousRows * component_size.button_height),
top: px(-verticalOffsetForParent - numberOfPreviousRows * component_size.button_height),
left: px(leftOffset),
borderLeft: border,
borderBottom: border,

View file

@ -3,7 +3,7 @@ import { lang } from "../../../common/misc/LanguageViewModel"
import { Keys, MailSetKind, MailState, SystemFolderType } from "../../../common/api/common/TutanotaConstants"
import type { Mail } from "../../../common/api/entities/tutanota/TypeRefs.js"
import { size } from "../../../common/gui/size"
import { component_size, size } from "../../../common/gui/size"
import { styles } from "../../../common/gui/styles"
import { Icon } from "../../../common/gui/base/Icon"
import { Icons } from "../../../common/gui/base/icons/Icons"
@ -74,7 +74,7 @@ export class MailListView implements Component<MailListViewAttrs> {
}
private readonly renderConfig: RenderConfig<Mail, MailRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Enabled,
createElement: (dom: HTMLElement) => {
const mailRow = new MailRow(

View file

@ -14,7 +14,7 @@ import {
setVisibility,
shouldAlwaysShowMultiselectCheckbox,
} from "../../../common/gui/SelectableRowContainer.js"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { noOp } from "@tutao/tutanota-utils"
import { setHTMLElementTextWithHighlighting, VirtualRow } from "../../../common/gui/base/ListUtils.js"
import { companyTeamLabel } from "../../../common/misc/ClientConstants.js"
@ -295,7 +295,7 @@ export class MailRow implements VirtualRow<Mail> {
{
"aria-hidden": "true",
style: {
marginLeft: px(size.checkbox_size + size.vpad_xs),
marginLeft: px(component_size.checkbox_size + size.vpad_xs),
},
},
[

View file

@ -1,4 +1,4 @@
import { px, size } from "../../../common/gui/size"
import { component_size, px, size } from "../../../common/gui/size"
import m, { Children, Component, Vnode } from "mithril"
import stream from "mithril/stream"
import { windowFacade, windowSizeListener } from "../../../common/misc/WindowFacade"
@ -226,7 +226,7 @@ export class MailViewer implements Component<MailViewerAttrs> {
},
style: {
height: "24px",
width: px(size.button_height_compact),
width: px(component_size.button_height_compact),
},
}),
),
@ -467,7 +467,7 @@ export class MailViewer implements Component<MailViewerAttrs> {
quoteIndicator,
m(Icon, {
icon: Icons.More,
class: "icon-xl mlr",
class: "icon-32 mlr",
container: "div",
style: {
fill: theme.on_surface_variant,

View file

@ -6,7 +6,7 @@ import { LabelsPopupOpts, ShowMoveMailsDropdownOpts } from "./MailGuiUtils.js"
import { modal } from "../../../common/gui/base/Modal.js"
import type { MailViewerMoreActions } from "./MailViewerUtils.js"
import { multipleMailViewerMoreActions } from "./MailViewerUtils.js"
import { px, size } from "../../../common/gui/size.js"
import { component_size, px, size } from "../../../common/gui/size.js"
import { noOp } from "@tutao/tutanota-utils"
export interface MobileMailActionBarAttrs {
@ -50,7 +50,7 @@ export class MobileMailActionBar implements Component<MobileMailActionBarAttrs>
private placeholder() {
return m("", {
style: {
width: px(size.button_height),
width: px(component_size.button_height),
},
})
}

View file

@ -53,7 +53,7 @@ export class SearchBarOverlay implements Component<SearchBarOverlayAttrs> {
{
style: {
height: px(52),
"border-left": px(size.border_selection) + " solid transparent",
"border-left": px(size.radius_4) + " solid transparent",
},
// avoid closing overlay before the click event can be received
onmousedown: (e: MouseEvent) => e.preventDefault(),
@ -97,7 +97,7 @@ export class SearchBarOverlay implements Component<SearchBarOverlayAttrs> {
{
style: {
height: px(52),
borderLeft: `${px(size.border_selection)} solid transparent`,
borderLeft: `${px(size.radius_4)} solid transparent`,
},
},
[
@ -150,7 +150,7 @@ export class SearchBarOverlay implements Component<SearchBarOverlayAttrs> {
{
style: {
height: px(52),
borderLeft: `${px(size.border_selection)} solid transparent`,
borderLeft: `${px(size.radius_4)} solid transparent`,
},
},
[

View file

@ -4,7 +4,7 @@ import { downcast, isSameTypeRef, TypeRef } from "@tutao/tutanota-utils"
import { MailRow } from "../../mail/view/MailRow"
import { ListElementListModel } from "../../../common/misc/ListElementListModel.js"
import { List, ListAttrs, MultiselectMode, RenderConfig } from "../../../common/gui/base/List.js"
import { size } from "../../../common/gui/size.js"
import { component_size, size } from "../../../common/gui/size.js"
import { KindaContactRow } from "../../contacts/view/ContactListView.js"
import { SearchableTypes } from "./SearchViewModel.js"
import { CalendarEvent, CalendarEventTypeRef, Contact, ContactTypeRef, Mail, MailFolder } from "../../../common/api/entities/tutanota/TypeRefs.js"
@ -116,7 +116,7 @@ export class SearchListView implements Component<SearchListViewAttrs> {
}
private readonly calendarRenderConfig: RenderConfig<SearchResultListEntry, SearchResultListRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Disabled,
swipe: null,
createElement: (dom) => {
@ -127,7 +127,7 @@ export class SearchListView implements Component<SearchListViewAttrs> {
}
private readonly mailRenderConfig: RenderConfig<SearchResultListEntry, SearchResultListRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Enabled,
swipe: null,
createElement: (dom) => {
@ -145,7 +145,7 @@ export class SearchListView implements Component<SearchListViewAttrs> {
}
private readonly contactRenderConfig: RenderConfig<SearchResultListEntry, SearchResultListRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Enabled,
swipe: null,
createElement: (dom) => {

View file

@ -3,7 +3,7 @@ import type { KnowledgeBaseEntry, TemplateGroupRoot } from "../../common/api/ent
import { KnowledgeBaseEntryTypeRef } from "../../common/api/entities/tutanota/TypeRefs.js"
import { lang } from "../../common/misc/LanguageViewModel"
import { size } from "../../common/gui/size"
import { component_size, size } from "../../common/gui/size"
import { EntityClient } from "../../common/api/common/EntityClient"
import { isSameId, listIdPart } from "../../common/api/common/utils/EntityUtils"
import { hasCapabilityOnGroup } from "../../common/sharing/GroupUtils"
@ -43,7 +43,7 @@ export class KnowledgeBaseListView implements UpdatableSettingsViewer {
private listModel: ListElementListModel<KnowledgeBaseEntry>
private listStateSubscription: Stream<unknown> | null = null
private readonly renderConfig: RenderConfig<KnowledgeBaseEntry, KnowledgeBaseRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Disabled,
swipe: null,
createElement: (dom) => {

View file

@ -76,7 +76,7 @@ export class MailExportSettings implements Component<MailExportSettingsAttrs> {
m(Icon, {
icon: BootIcons.Progress,
class: "flex-center items-center icon-progress-tiny icon-progress ml-s",
size: IconSize.Medium,
size: IconSize.PX24,
}),
m(IconButton, {
title: "cancel_action",

View file

@ -805,7 +805,7 @@ export class SettingsView extends BaseTopLevelView implements TopLevelView<Setti
text: m(".pl-s", lang.getTranslation("supportMenu_label").text),
icon: m(Icon, {
icon: Icons.SpeechBubbleFill,
size: IconSize.Medium,
size: IconSize.PX24,
class: "center-h",
container: "div",
style: { fill: theme.on_surface_variant },

View file

@ -20,7 +20,7 @@ import ColumnEmptyMessageBox from "../../common/gui/base/ColumnEmptyMessageBox.j
import { theme } from "../../common/gui/theme.js"
import { Icons } from "../../common/gui/base/icons/Icons.js"
import { List, ListAttrs, MultiselectMode, RenderConfig } from "../../common/gui/base/List.js"
import { size } from "../../common/gui/size.js"
import { component_size, size } from "../../common/gui/size.js"
import { TemplateDetailsViewer } from "./TemplateDetailsViewer.js"
import { listSelectionKeyboardShortcuts, onlySingleSelection, VirtualRow } from "../../common/gui/base/ListUtils.js"
import { IconButton } from "../../common/gui/base/IconButton.js"
@ -43,7 +43,7 @@ export class TemplateListView implements UpdatableSettingsViewer {
private listModel: ListElementListModel<EmailTemplate>
private listStateSubscription: Stream<unknown> | null = null
private readonly renderConfig: RenderConfig<EmailTemplate, TemplateRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Disabled,
swipe: null,
createElement: (dom) => {

View file

@ -14,7 +14,7 @@ import { GroupDetailsModel } from "./GroupDetailsModel.js"
import { SelectableRowContainer, SelectableRowSelectedSetter, setVisibility } from "../../../common/gui/SelectableRowContainer.js"
import Stream from "mithril/stream"
import { List, ListAttrs, MultiselectMode, RenderConfig } from "../../../common/gui/base/List.js"
import { size } from "../../../common/gui/size.js"
import { component_size, size } from "../../../common/gui/size.js"
import { ListElementListModel } from "../../../common/misc/ListElementListModel.js"
import { compareGroupInfos } from "../../../common/api/common/utils/GroupUtils.js"
import { NotFoundError } from "../../../common/api/common/error/RestError.js"
@ -36,7 +36,7 @@ export class GroupListView implements UpdatableSettingsViewer {
private searchQuery: string = ""
private listModel: ListElementListModel<GroupInfo>
private readonly renderConfig: RenderConfig<GroupInfo, GroupRow> = {
itemHeight: size.list_row_height,
itemHeight: component_size.list_row_height,
multiselectionAllowed: MultiselectMode.Disabled,
swipe: null,
createElement: (dom) => {

View file

@ -1,5 +1,5 @@
import m, { Children, Component, Vnode } from "mithril"
import { px, size } from "../../../common/gui/size"
import { component_size, px, size } from "../../../common/gui/size"
import { Keys } from "../../../common/api/common/TutanotaConstants"
import { TemplatePopupModel } from "../model/TemplatePopupModel.js"
import { isKeyPressed } from "../../../common/misc/KeyManager"
@ -37,7 +37,7 @@ export class TemplateExpander implements Component<TemplateExpanderAttrs> {
{
style: {
// maxHeight has to be set, because otherwise the content would overflow outside the flexbox (-44 because of header height)
maxHeight: px(TEMPLATE_POPUP_HEIGHT - size.button_height),
maxHeight: px(TEMPLATE_POPUP_HEIGHT - component_size.button_height),
},
onkeydown: (e: KeyboardEvent) => {
if (isKeyPressed(e.key, Keys.TAB)) {