mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
Redesign deck options inputs (#2082)
* Create _input-mixins.scss * Use button-mixins on more elements * Replace <select> tag with custom Select component * Fix RevertButton causing cursor: pointer when hidden * Increase SaveButton chevron width * Hide floating component box-shadow when inactive * Rework SpinBox and move it into components * Run eslint and prettier * Remove leftover options prop * Pass disabled array to EnumSelector again * Update MapperRow.svelte * Darken QHeaderView border color Slipping this in without an extra PR. * Adjust disabled color, border and cursor * Remove redundant icon definition from stylesheets * Fix deck options initial config * Fix z-index issues in change notetype screen It might be best to handle z-index locally in each user component instead of hard-coded component values. * Give web SpinBox a horizontal design * Give QRadioButton the same treatment as QCheckBox in #2079 * Fix unused CSS selector warning with base button-mixin * Remove redundant import * Fix deck options save button * Delete input-mixins and remove unused down-arrow * Run eslint on change-notetype * Run eslint on components
This commit is contained in:
parent
6a7f2d8a79
commit
23e6b2123e
45 changed files with 596 additions and 505 deletions
|
@ -353,6 +353,7 @@ class AnkiApp(QApplication):
|
||||||
(
|
(
|
||||||
QPushButton,
|
QPushButton,
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
|
QRadioButton,
|
||||||
# classes with PyQt5 compatibility proxy
|
# classes with PyQt5 compatibility proxy
|
||||||
without_qt5_compat_wrapper(QToolButton),
|
without_qt5_compat_wrapper(QToolButton),
|
||||||
without_qt5_compat_wrapper(QTabBar),
|
without_qt5_compat_wrapper(QTabBar),
|
||||||
|
|
|
@ -16,42 +16,42 @@
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="3" column="0">
|
<item row="3" column="0" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="radioAhead">
|
<widget class="QRadioButton" name="radioAhead">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>custom_study_review_ahead</string>
|
<string>custom_study_review_ahead</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="radioForgot">
|
<widget class="QRadioButton" name="radioForgot">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>custom_study_review_forgotten_cards</string>
|
<string>custom_study_review_forgotten_cards</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="radioNew">
|
<widget class="QRadioButton" name="radioNew">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>custom_study_increase_todays_new_card_limit</string>
|
<string>custom_study_increase_todays_new_card_limit</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="radioRev">
|
<widget class="QRadioButton" name="radioRev">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>custom_study_increase_todays_review_card_limit</string>
|
<string>custom_study_increase_todays_review_card_limit</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="5" column="0" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="radioCram">
|
<widget class="QRadioButton" name="radioCram">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>custom_study_study_by_card_state_or_tag</string>
|
<string>custom_study_study_by_card_state_or_tag</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="radioPreview">
|
<widget class="QRadioButton" name="radioPreview">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>custom_study_preview_new_cards</string>
|
<string>custom_study_preview_new_cards</string>
|
||||||
|
|
|
@ -155,7 +155,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1" alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="sortField">
|
<widget class="QRadioButton" name="sortField">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>fields_sort_by_this_field_in_the</string>
|
<string>fields_sort_by_this_field_in_the</string>
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="preview_front">
|
<widget class="QRadioButton" name="preview_front">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">FRONT</string>
|
<string notr="true">FRONT</string>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="preview_back">
|
<widget class="QRadioButton" name="preview_back">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">BACK</string>
|
<string notr="true">BACK</string>
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="groups">
|
<widget class="QRadioButton" name="groups">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">deck</string>
|
<string notr="true">deck</string>
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="all">
|
<widget class="QRadioButton" name="all">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">collection</string>
|
<string notr="true">collection</string>
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="month">
|
<widget class="QRadioButton" name="month">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">1 month</string>
|
<string notr="true">1 month</string>
|
||||||
|
@ -110,14 +110,14 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="year">
|
<widget class="QRadioButton" name="year">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">1 year</string>
|
<string notr="true">1 year</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="life">
|
<widget class="QRadioButton" name="life">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">deck life</string>
|
<string notr="true">deck life</string>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="front_button">
|
<widget class="QRadioButton" name="front_button">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="back_button">
|
<widget class="QRadioButton" name="back_button">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item alignment="Qt::AlignLeft">
|
||||||
<widget class="QRadioButton" name="style_button">
|
<widget class="QRadioButton" name="style_button">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
|
|
|
@ -233,7 +233,7 @@ QHeaderView {{
|
||||||
background: {tm.var(colors.CANVAS)};
|
background: {tm.var(colors.CANVAS)};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section {{
|
QHeaderView::section {{
|
||||||
border: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
border: 1px solid {tm.var(colors.BORDER)};
|
||||||
background: {
|
background: {
|
||||||
button_gradient(
|
button_gradient(
|
||||||
tm.var(colors.BUTTON_GRADIENT_START),
|
tm.var(colors.BUTTON_GRADIENT_START),
|
||||||
|
@ -261,19 +261,19 @@ QHeaderView::section:hover {{
|
||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:first {{
|
QHeaderView::section:first {{
|
||||||
border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
border-left: 1px solid {tm.var(colors.BORDER)};
|
||||||
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:!first {{
|
QHeaderView::section:!first {{
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:last {{
|
QHeaderView::section:last {{
|
||||||
border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
border-right: 1px solid {tm.var(colors.BORDER)};
|
||||||
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
QHeaderView::section:only-one {{
|
QHeaderView::section:only-one {{
|
||||||
border-left: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
border-left: 1px solid {tm.var(colors.BORDER)};
|
||||||
border-right: 1px solid {tm.var(colors.BORDER_SUBTLE)};
|
border-right: 1px solid {tm.var(colors.BORDER)};
|
||||||
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-left-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
border-top-right-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
}}
|
}}
|
||||||
|
@ -368,24 +368,34 @@ QSpinBox::down-arrow:off {{
|
||||||
|
|
||||||
def checkbox_styles(tm: ThemeManager) -> str:
|
def checkbox_styles(tm: ThemeManager) -> str:
|
||||||
return f"""
|
return f"""
|
||||||
QCheckBox {{
|
QCheckBox,
|
||||||
|
QRadioButton {{
|
||||||
spacing: 8px;
|
spacing: 8px;
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator {{
|
QCheckBox::indicator,
|
||||||
|
QRadioButton::indicator {{
|
||||||
border: 1px solid {tm.var(colors.BUTTON_BORDER)};
|
border: 1px solid {tm.var(colors.BUTTON_BORDER)};
|
||||||
border-radius: {tm.var(props.BORDER_RADIUS)};
|
|
||||||
background: {tm.var(colors.CANVAS_INSET)};
|
background: {tm.var(colors.CANVAS_INSET)};
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}}
|
}}
|
||||||
|
QCheckBox::indicator {{
|
||||||
|
border-radius: {tm.var(props.BORDER_RADIUS)};
|
||||||
|
}}
|
||||||
|
QRadioButton::indicator {{
|
||||||
|
border-radius: 8px;
|
||||||
|
}}
|
||||||
QCheckBox::indicator:hover,
|
QCheckBox::indicator:hover,
|
||||||
QCheckBox::indicator:checked:hover {{
|
QCheckBox::indicator:checked:hover,
|
||||||
|
QRadioButton::indicator:hover,
|
||||||
|
QRadioButton::indicator:checked:hover {{
|
||||||
border: 2px solid {tm.var(colors.BORDER_STRONG)};
|
border: 2px solid {tm.var(colors.BORDER_STRONG)};
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator:checked {{
|
QCheckBox::indicator:checked,
|
||||||
|
QRadioButton::indicator:checked {{
|
||||||
image: url({tm.themed_icon("mdi:check")});
|
image: url({tm.themed_icon("mdi:check")});
|
||||||
}}
|
}}
|
||||||
QCheckBox::indicator:indeterminate {{
|
QCheckBox::indicator:indeterminate {{
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
rgba(black, $intensity);
|
rgba(black, $intensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-border-radius {
|
@mixin border-radius {
|
||||||
border-top-left-radius: var(--border-left-radius);
|
border-top-left-radius: var(--border-left-radius);
|
||||||
border-bottom-left-radius: var(--border-left-radius);
|
border-bottom-left-radius: var(--border-left-radius);
|
||||||
|
|
||||||
|
@ -19,39 +19,8 @@
|
||||||
border-bottom-right-radius: var(--border-right-radius);
|
border-bottom-right-radius: var(--border-right-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin base(
|
@mixin background($primary: false) {
|
||||||
$selector: button,
|
@if $primary {
|
||||||
$with-primary: false,
|
|
||||||
$with-hover: true,
|
|
||||||
$with-active: true,
|
|
||||||
$with-disabled: true
|
|
||||||
) {
|
|
||||||
#{$selector} {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border: 1px solid var(--button-border);
|
|
||||||
|
|
||||||
color: var(--fg);
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
var(--button-gradient-start) 0%,
|
|
||||||
var(--button-gradient-end) 100%
|
|
||||||
);
|
|
||||||
|
|
||||||
@if ($with-hover) {
|
|
||||||
&:hover {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
var(--button-hover-gradient-start) 0%,
|
|
||||||
var(--button-hover-gradient-end) 100%
|
|
||||||
);
|
|
||||||
|
|
||||||
border-color: var(--button-hover-border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@if ($with-primary) {
|
|
||||||
&.btn-primary {
|
|
||||||
color: white;
|
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
180deg,
|
180deg,
|
||||||
var(--button-primary-gradient-start) 0%,
|
var(--button-primary-gradient-start) 0%,
|
||||||
|
@ -63,31 +32,87 @@
|
||||||
var(--button-primary-hover-gradient-start) 0%,
|
var(--button-primary-hover-gradient-start) 0%,
|
||||||
var(--button-primary-hover-gradient-end) 100%
|
var(--button-primary-hover-gradient-end) 100%
|
||||||
);
|
);
|
||||||
|
border-color: var(--button-hover-border);
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--button-gradient-start) 0%,
|
||||||
|
var(--button-gradient-end) 100%
|
||||||
|
);
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--button-hover-gradient-start) 0%,
|
||||||
|
var(--button-hover-gradient-end) 100%
|
||||||
|
);
|
||||||
|
border-color: var(--button-hover-border);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin base(
|
||||||
|
$primary: false,
|
||||||
|
$border: true,
|
||||||
|
$with-hover: true,
|
||||||
|
$with-active: true,
|
||||||
|
$active-class: "",
|
||||||
|
$with-disabled: true
|
||||||
|
) {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
@if $border {
|
||||||
|
border: 1px solid var(--button-border);
|
||||||
|
} @else {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
@include background($primary);
|
||||||
|
|
||||||
|
@if ($primary) {
|
||||||
|
color: white;
|
||||||
|
} @else {
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
@if ($with-active) {
|
@if ($with-active) {
|
||||||
&:active {
|
&:active {
|
||||||
@include impressed-shadow(0.35);
|
@include impressed-shadow(0.35);
|
||||||
box-shadow: none;
|
|
||||||
border-color: var(--button-border);
|
border-color: var(--button-border);
|
||||||
}
|
}
|
||||||
|
@if ($active-class != "") {
|
||||||
|
&.#{$active-class} {
|
||||||
|
@include impressed-shadow(0.35);
|
||||||
|
border-color: var(--button-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@if ($with-disabled) {
|
@if ($with-disabled) {
|
||||||
&[disabled] {
|
&[disabled],
|
||||||
|
&[disabled]:hover {
|
||||||
|
cursor: not-allowed;
|
||||||
color: var(--fg-disabled);
|
color: var(--fg-disabled);
|
||||||
background-color: var(--button-gradient-end) !important;
|
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
border-color: var(--button-gradient-end) !important;
|
background-color: var(--button-gradient-end);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$focus-color: vars.color(shadow-focus);
|
$focus-color: var(--shadow-focus);
|
||||||
|
|
||||||
@function down-arrow($color) {
|
@mixin select($with-disabled: true) {
|
||||||
@return url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='transparent' stroke='#{$color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
pointer-events: all;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
@include base($with-disabled: $with-disabled);
|
||||||
|
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
|
||||||
|
&.rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,8 @@ $vars: (
|
||||||
dark: palette(lightgray, 3),
|
dark: palette(lightgray, 3),
|
||||||
),
|
),
|
||||||
disabled: (
|
disabled: (
|
||||||
light: palette(darkgray, 2),
|
light: palette(lightgray, 9),
|
||||||
dark: palette(lightgray, 8),
|
dark: palette(darkgray, 0),
|
||||||
),
|
),
|
||||||
faint: (
|
faint: (
|
||||||
light: palette(lightgray, 7),
|
light: palette(lightgray, 7),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@use "vars";
|
@use "vars";
|
||||||
@use "scrollbar";
|
@use "scrollbar";
|
||||||
|
@use "button-mixins" as button;
|
||||||
|
|
||||||
$body-color: var(--fg);
|
$body-color: var(--fg);
|
||||||
$body-bg: var(--canvas);
|
$body-bg: var(--canvas);
|
||||||
|
@ -79,6 +80,11 @@ samp {
|
||||||
background-position: left 0.75rem center;
|
background-position: left 0.75rem center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.form-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid var(--border-focus);
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
.night-mode .form-select:disabled {
|
.night-mode .form-select:disabled {
|
||||||
background-color: var(--fg-disabled);
|
background-color: var(--fg-disabled);
|
||||||
|
@ -88,3 +94,20 @@ samp {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
animation: none !important;
|
animation: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
@include button.background;
|
||||||
|
@include button.border-radius;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&.focus {
|
||||||
|
border: 1px solid var(--border-focus);
|
||||||
|
}
|
||||||
|
option {
|
||||||
|
background: var(--canvas-elevated);
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@use "vars";
|
@use "vars";
|
||||||
|
@use "button-mixins" as button;
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--focus-color: #{vars.palette-of(shadow-focus)};
|
--focus-color: #{vars.palette-of(shadow-focus)};
|
||||||
|
@ -21,30 +22,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
-webkit-appearance: none;
|
@include button.base;
|
||||||
color: vars.color(fg);
|
border-radius: var(--border-radius);
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
vars.color(button-gradient-start) 0%,
|
|
||||||
vars.color(button-gradient-end) 100%
|
|
||||||
);
|
|
||||||
border: 1px solid vars.color(button-border);
|
|
||||||
|
|
||||||
border-radius: vars.prop(border-radius);
|
|
||||||
padding: 3px 10px 3px;
|
padding: 3px 10px 3px;
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
box-shadow: 0 0 0 1px var(--focus-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
vars.color(button-hover-gradient-start) 0%,
|
|
||||||
vars.color(button-hover-gradient-end) 100%
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import Col from "../components/Col.svelte";
|
import Col from "../components/Col.svelte";
|
||||||
import Container from "../components/Container.svelte";
|
import Container from "../components/Container.svelte";
|
||||||
import Row from "../components/Row.svelte";
|
import Row from "../components/Row.svelte";
|
||||||
|
import StickyContainer from "../components/StickyContainer.svelte";
|
||||||
import * as tr from "../lib/ftl";
|
import * as tr from "../lib/ftl";
|
||||||
import { ChangeNotetypeState, MapContext } from "./lib";
|
import { ChangeNotetypeState, MapContext } from "./lib";
|
||||||
import Mapper from "./Mapper.svelte";
|
import Mapper from "./Mapper.svelte";
|
||||||
|
@ -20,20 +21,27 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:offsetHeight={offset}>
|
<div bind:offsetHeight={offset}>
|
||||||
|
<StickyContainer
|
||||||
|
--gutter-block="0.1rem"
|
||||||
|
--gutter-inline="0.25rem"
|
||||||
|
--sticky-borders="0 0 1px"
|
||||||
|
--z-index="4"
|
||||||
|
>
|
||||||
<NotetypeSelector {state} />
|
<NotetypeSelector {state} />
|
||||||
|
</StickyContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="scrollArea" style="--offset: {offset}px; --gutter-inline: 0.25rem;">
|
<div id="scrollArea" style="--offset: {offset}px; --gutter-inline: 0.25rem;">
|
||||||
<Row class="gx-0" --cols={2}>
|
<Row class="gx-0" --cols={2}>
|
||||||
<Col --col-size={1} breakpoint="md">
|
<Col --col-size={1} breakpoint="md">
|
||||||
<Container>
|
<Container>
|
||||||
<StickyHeader {state} ctx={MapContext.Field} />
|
<StickyHeader {state} ctx={MapContext.Field} --z-index="2" />
|
||||||
<Mapper {state} ctx={MapContext.Field} />
|
<Mapper {state} ctx={MapContext.Field} />
|
||||||
</Container>
|
</Container>
|
||||||
</Col>
|
</Col>
|
||||||
<Col --col-size={1} breakpoint="md">
|
<Col --col-size={1} breakpoint="md">
|
||||||
<Container>
|
<Container>
|
||||||
<StickyHeader {state} ctx={MapContext.Template} />
|
<StickyHeader {state} ctx={MapContext.Template} --z-index="2" />
|
||||||
{#if $info.templates}
|
{#if $info.templates}
|
||||||
<Mapper {state} ctx={MapContext.Template} />
|
<Mapper {state} ctx={MapContext.Template} />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
@ -5,6 +5,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Col from "../components/Col.svelte";
|
import Col from "../components/Col.svelte";
|
||||||
import Row from "../components/Row.svelte";
|
import Row from "../components/Row.svelte";
|
||||||
|
import Select from "../components/Select.svelte";
|
||||||
|
import SelectOption from "../components/SelectOption.svelte";
|
||||||
import type { ChangeNotetypeState, MapContext } from "./lib";
|
import type { ChangeNotetypeState, MapContext } from "./lib";
|
||||||
|
|
||||||
export let state: ChangeNotetypeState;
|
export let state: ChangeNotetypeState;
|
||||||
|
@ -13,24 +15,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
const info = state.info;
|
const info = state.info;
|
||||||
|
|
||||||
function onChange(evt: Event) {
|
let oldIndex = $info.getOldIndex(ctx, newIndex);
|
||||||
const oldIdx = parseInt((evt.target as HTMLSelectElement).value, 10);
|
|
||||||
state.setOldIndex(ctx, newIndex, oldIdx);
|
const options = $info.getOldNamesIncludingNothing(ctx);
|
||||||
}
|
$: state.setOldIndex(ctx, newIndex, oldIndex);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Row --cols={2}>
|
<Row --cols={2}>
|
||||||
<Col --col-size={1}>
|
<Col --col-size={1}>
|
||||||
<!-- svelte-ignore a11y-no-onchange -->
|
<!-- svelte-ignore a11y-no-onchange -->
|
||||||
<select
|
<Select current={options[oldIndex]}>
|
||||||
value={$info.getOldIndex(ctx, newIndex)}
|
{#each options as name, idx}
|
||||||
class="form-select"
|
<SelectOption on:select={() => (oldIndex = idx)}>{name}</SelectOption>
|
||||||
on:change={onChange}
|
|
||||||
>
|
|
||||||
{#each $info.getOldNamesIncludingNothing(ctx) as name, idx}
|
|
||||||
<option value={idx}>{name}</option>
|
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</Select>
|
||||||
</Col>
|
</Col>
|
||||||
<Col --col-size={1}>
|
<Col --col-size={1}>
|
||||||
{$info.getNewName(ctx, newIndex)}
|
{$info.getNewName(ctx, newIndex)}
|
||||||
|
|
|
@ -7,9 +7,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import ButtonGroup from "../components/ButtonGroup.svelte";
|
import ButtonGroup from "../components/ButtonGroup.svelte";
|
||||||
import ButtonToolbar from "../components/ButtonToolbar.svelte";
|
import ButtonToolbar from "../components/ButtonToolbar.svelte";
|
||||||
import LabelButton from "../components/LabelButton.svelte";
|
import LabelButton from "../components/LabelButton.svelte";
|
||||||
import SelectButton from "../components/SelectButton.svelte";
|
import Select from "../components/Select.svelte";
|
||||||
import SelectOption from "../components/SelectOption.svelte";
|
import SelectOption from "../components/SelectOption.svelte";
|
||||||
import StickyContainer from "../components/StickyContainer.svelte";
|
|
||||||
import { arrowLeftIcon, arrowRightIcon } from "./icons";
|
import { arrowLeftIcon, arrowRightIcon } from "./icons";
|
||||||
import type { ChangeNotetypeState } from "./lib";
|
import type { ChangeNotetypeState } from "./lib";
|
||||||
import SaveButton from "./SaveButton.svelte";
|
import SaveButton from "./SaveButton.svelte";
|
||||||
|
@ -17,19 +16,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export let state: ChangeNotetypeState;
|
export let state: ChangeNotetypeState;
|
||||||
const notetypes = state.notetypes;
|
const notetypes = state.notetypes;
|
||||||
const info = state.info;
|
const info = state.info;
|
||||||
|
let value: number = 0;
|
||||||
|
|
||||||
async function blur(event: Event): Promise<void> {
|
$: state.setTargetNotetypeIndex(value);
|
||||||
await state.setTargetNotetypeIndex(
|
$: options = Array.from($notetypes, (notetype) => notetype.name);
|
||||||
parseInt((event.target! as HTMLSelectElement).value),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<StickyContainer
|
|
||||||
--gutter-block="0.1rem"
|
|
||||||
--gutter-inline="0.25rem"
|
|
||||||
--sticky-borders="0 0 1px"
|
|
||||||
>
|
|
||||||
<ButtonToolbar class="justify-content-between" size={2.3} wrap={false}>
|
<ButtonToolbar class="justify-content-between" size={2.3} wrap={false}>
|
||||||
<LabelButton disabled={true}>
|
<LabelButton disabled={true}>
|
||||||
{$info.oldNotetypeName}
|
{$info.oldNotetypeName}
|
||||||
|
@ -42,15 +34,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
{/if}
|
{/if}
|
||||||
</Badge>
|
</Badge>
|
||||||
<ButtonGroup class="flex-grow-1">
|
<ButtonGroup class="flex-grow-1">
|
||||||
<SelectButton class="flex-grow-1" on:change={blur}>
|
<Select class="flex-grow-1" current={options[value]}>
|
||||||
{#each $notetypes as entry}
|
{#each options as option, idx}
|
||||||
<SelectOption value={String(entry.idx)} selected={entry.current}>
|
<SelectOption on:select={() => (value = idx)}>{option}</SelectOption>
|
||||||
{entry.name}
|
|
||||||
</SelectOption>
|
|
||||||
{/each}
|
{/each}
|
||||||
</SelectButton>
|
</Select>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<SaveButton {state} />
|
<SaveButton {state} />
|
||||||
</ButtonToolbar>
|
</ButtonToolbar>
|
||||||
</StickyContainer>
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<LabelButton
|
<LabelButton
|
||||||
theme="primary"
|
primary
|
||||||
tooltip={getPlatformString(keyCombination)}
|
tooltip={getPlatformString(keyCombination)}
|
||||||
on:click={save}
|
on:click={save}
|
||||||
--border-left-radius="5px"
|
--border-left-radius="5px"
|
||||||
|
|
|
@ -27,8 +27,3 @@ html {
|
||||||
padding: 0.5em 0.5em 1em 0.5em;
|
padding: 0.5em 0.5em 1em 0.5em;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
// override the default down arrow colour in <select> elements
|
|
||||||
.night-mode select {
|
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23FFFFFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ _ts_deps = [
|
||||||
"@npm//@floating-ui/dom",
|
"@npm//@floating-ui/dom",
|
||||||
"@npm//bootstrap",
|
"@npm//bootstrap",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
|
"@npm//@mdi",
|
||||||
]
|
]
|
||||||
|
|
||||||
compile_svelte(
|
compile_svelte(
|
||||||
|
|
|
@ -3,17 +3,16 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
|
||||||
|
|
||||||
export let id: string | undefined = undefined;
|
export let id: string | undefined = undefined;
|
||||||
let className = "";
|
let className = "";
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
let buttonRef: HTMLButtonElement;
|
export let buttonRef: HTMLButtonElement | undefined = undefined;
|
||||||
|
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
|
|
||||||
export let active = false;
|
export let active = false;
|
||||||
|
export let disabled = false;
|
||||||
|
|
||||||
$: if (buttonRef && active) {
|
$: if (buttonRef && active) {
|
||||||
/* buttonRef.scrollIntoView({ behavior: "smooth", block: "start" }); */
|
/* buttonRef.scrollIntoView({ behavior: "smooth", block: "start" }); */
|
||||||
|
@ -33,8 +32,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
tabindex={tabbable ? 0 : -1}
|
tabindex={tabbable ? 0 : -1}
|
||||||
class="dropdown-item {className}"
|
class="dropdown-item {className}"
|
||||||
class:active
|
class:active
|
||||||
class:btn-day={!$pageTheme.isDark}
|
class:disabled
|
||||||
class:btn-night={$pageTheme.isDark}
|
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
on:mouseenter
|
on:mouseenter
|
||||||
on:focus
|
on:focus
|
||||||
|
@ -46,11 +44,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use "sass/button-mixins" as button;
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
font-size: var(--dropdown-font-size, calc(0.8 * var(--base-font-size)));
|
font-size: var(--dropdown-font-size, calc(0.8 * var(--base-font-size)));
|
||||||
|
|
||||||
|
@ -58,19 +55,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
color: var(--fg);
|
||||||
|
|
||||||
&:active,
|
&:hover {
|
||||||
&.active {
|
background: var(--highlight-bg);
|
||||||
background-color: button.$focus-color;
|
color: var(--highlight-fg);
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-day {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-night {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,7 +3,6 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
|
||||||
import IconConstrain from "./IconConstrain.svelte";
|
import IconConstrain from "./IconConstrain.svelte";
|
||||||
|
|
||||||
export let id: string | undefined = undefined;
|
export let id: string | undefined = undefined;
|
||||||
|
@ -11,6 +10,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
|
export let primary = false;
|
||||||
export let active = false;
|
export let active = false;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let tabbable = false;
|
export let tabbable = false;
|
||||||
|
@ -22,10 +22,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
<button
|
<button
|
||||||
{id}
|
{id}
|
||||||
class="icon-button btn {className}"
|
class="icon-button {className}"
|
||||||
class:active
|
class:active
|
||||||
class:btn-day={!$pageTheme.isDark}
|
class:primary
|
||||||
class:btn-night={$pageTheme.isDark}
|
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
{disabled}
|
{disabled}
|
||||||
tabindex={tabbable ? 0 : -1}
|
tabindex={tabbable ? 0 : -1}
|
||||||
|
@ -41,12 +40,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
@use "sass/button-mixins" as button;
|
@use "sass/button-mixins" as button;
|
||||||
|
|
||||||
.icon-button {
|
.icon-button {
|
||||||
|
@include button.base($active-class: active);
|
||||||
|
&.primary {
|
||||||
|
@include button.base($primary: true);
|
||||||
|
}
|
||||||
|
@include button.border-radius;
|
||||||
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: var(--base-font-size);
|
font-size: var(--base-font-size);
|
||||||
height: var(--buttons-size);
|
height: var(--buttons-size);
|
||||||
|
min-width: calc(var(--buttons-size) * 0.75);
|
||||||
@include button.btn-border-radius;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include button.base(".icon-button");
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -22,7 +22,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
vertical-align: var(--icon-align, middle);
|
vertical-align: var(--icon-align, middle);
|
||||||
|
|
||||||
/* constrain icon */
|
/* constrain icon */
|
||||||
width: calc((var(--buttons-size, 22px) - 2px) * var(--width-multiplier));
|
min-width: calc((var(--buttons-size, 22px) - 2px) * var(--width-multiplier));
|
||||||
height: calc(var(--buttons-size, 22px) - 2px);
|
height: calc(var(--buttons-size, 22px) - 2px);
|
||||||
|
|
||||||
& > :global(svg),
|
& > :global(svg),
|
||||||
|
|
|
@ -5,16 +5,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
|
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
|
||||||
|
|
||||||
export let id: string | undefined = undefined;
|
export let id: string | undefined = undefined;
|
||||||
let className: string = "";
|
let className: string = "";
|
||||||
export { className as class };
|
export { className as class };
|
||||||
export let theme = "anki";
|
export let primary = false;
|
||||||
|
|
||||||
function extendClassName(className: string, theme: string): string {
|
|
||||||
return `btn ${theme !== "anki" ? `btn-${theme}` : ""}${className}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
export let active = false;
|
export let active = false;
|
||||||
|
@ -30,10 +24,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<button
|
<button
|
||||||
bind:this={buttonRef}
|
bind:this={buttonRef}
|
||||||
{id}
|
{id}
|
||||||
class="label-button {extendClassName(className, theme)}"
|
class="label-button {className}"
|
||||||
class:active
|
class:active
|
||||||
class:btn-day={theme === "anki" && !$pageTheme.isDark}
|
class:primary
|
||||||
class:btn-night={theme === "anki" && $pageTheme.isDark}
|
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
{disabled}
|
{disabled}
|
||||||
tabindex={tabbable ? 0 : -1}
|
tabindex={tabbable ? 0 : -1}
|
||||||
|
@ -47,6 +40,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
@use "sass/button-mixins" as button;
|
@use "sass/button-mixins" as button;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
@include button.base($active-class: active);
|
||||||
|
&.primary {
|
||||||
|
@include button.base($primary: true);
|
||||||
|
}
|
||||||
|
@include button.border-radius;
|
||||||
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -54,9 +53,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
font-size: var(--base-font-size);
|
font-size: var(--base-font-size);
|
||||||
width: auto;
|
width: auto;
|
||||||
height: var(--buttons-size);
|
height: var(--buttons-size);
|
||||||
|
|
||||||
@include button.btn-border-radius;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include button.base($with-primary: true);
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,19 +2,29 @@
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script>
|
<script lang="ts">
|
||||||
|
import { slide } from "svelte/transition";
|
||||||
|
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
import { pageTheme } from "../sveltelib/theme";
|
||||||
|
|
||||||
|
export let scrollable = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="popover" class:dark={$pageTheme.isDark} on:mousedown|preventDefault>
|
<div
|
||||||
|
class="popover"
|
||||||
|
class:scrollable
|
||||||
|
class:dark={$pageTheme.isDark}
|
||||||
|
transition:slide={{ duration: 200 }}
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@use "sass/vars";
|
||||||
.popover {
|
.popover {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: var(--canvas-elevated);
|
background-color: var(--canvas-elevated);
|
||||||
min-width: 1rem;
|
min-width: var(--popover-width, 1rem);
|
||||||
max-width: 95vw;
|
max-width: 95vw;
|
||||||
|
|
||||||
/* Needs this much space for FloatingArrow to be positioned */
|
/* Needs this much space for FloatingArrow to be positioned */
|
||||||
|
@ -24,17 +34,21 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
|
||||||
/* outer border */
|
/* outer border */
|
||||||
border: 1px solid #b6b6b6;
|
border: 1px solid vars.palette(lightgray, 6);
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
border-color: #060606;
|
border-color: vars.palette(darkgray, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* inner border */
|
/* inner border */
|
||||||
box-shadow: inset 0 0 0 1px #eeeeee;
|
box-shadow: inset 0 0 0 1px vars.palette(lightgray, 3);
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
box-shadow: inset 0 0 0 1px #565656;
|
box-shadow: inset 0 0 0 1px vars.palette(darkgray, 2);
|
||||||
|
}
|
||||||
|
&.scrollable {
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow: hidden auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
86
ts/components/Select.svelte
Normal file
86
ts/components/Select.svelte
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<!--
|
||||||
|
Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import IconConstrain from "./IconConstrain.svelte";
|
||||||
|
import { chevronDown } from "./icons";
|
||||||
|
import Popover from "./Popover.svelte";
|
||||||
|
import WithFloating from "./WithFloating.svelte";
|
||||||
|
|
||||||
|
export let id: string | undefined = undefined;
|
||||||
|
let className = "";
|
||||||
|
export { className as class };
|
||||||
|
export let disabled = false;
|
||||||
|
export let current: string = "";
|
||||||
|
|
||||||
|
export let tooltip: string | undefined = undefined;
|
||||||
|
|
||||||
|
const rtl: boolean = window.getComputedStyle(document.body).direction == "rtl";
|
||||||
|
export let element: HTMLElement | undefined = undefined;
|
||||||
|
let hover = false;
|
||||||
|
|
||||||
|
let showFloating = false;
|
||||||
|
let clientWidth: number;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<WithFloating
|
||||||
|
show={showFloating}
|
||||||
|
placement="bottom"
|
||||||
|
offset={0}
|
||||||
|
hideArrow
|
||||||
|
inline
|
||||||
|
closeOnInsideClick
|
||||||
|
on:close={() => (showFloating = false)}
|
||||||
|
let:asReference
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
{id}
|
||||||
|
class="{className} select-container"
|
||||||
|
class:rtl
|
||||||
|
class:hover
|
||||||
|
{disabled}
|
||||||
|
title={tooltip}
|
||||||
|
tabindex="-1"
|
||||||
|
on:mouseenter={() => (hover = true)}
|
||||||
|
on:mouseleave={() => (hover = false)}
|
||||||
|
on:click={() => (showFloating = !showFloating)}
|
||||||
|
bind:this={element}
|
||||||
|
use:asReference
|
||||||
|
bind:clientWidth
|
||||||
|
>
|
||||||
|
{current}
|
||||||
|
<div class="chevron">
|
||||||
|
<IconConstrain iconSize={80}>
|
||||||
|
{@html chevronDown}
|
||||||
|
</IconConstrain>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Popover slot="floating" scrollable --popover-width="{clientWidth}px">
|
||||||
|
<slot />
|
||||||
|
</Popover>
|
||||||
|
</WithFloating>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use "sass/button-mixins" as button;
|
||||||
|
.select-container {
|
||||||
|
@include button.select($with-disabled: false);
|
||||||
|
padding: 0.2rem 2rem 0.2rem 0.75rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
height: var(--buttons-size, 100%);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 0 0 auto;
|
||||||
|
border-left: 1px solid var(--button-border);
|
||||||
|
}
|
||||||
|
:global([dir="rtl"]) {
|
||||||
|
.chevron {
|
||||||
|
inset: 0 auto 0 0;
|
||||||
|
border-left: none;
|
||||||
|
border-right: 1px solid var(--button-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,82 +0,0 @@
|
||||||
<!--
|
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
-->
|
|
||||||
<script lang="ts">
|
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
|
||||||
|
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
|
||||||
|
|
||||||
const rtl: boolean = window.getComputedStyle(document.body).direction == "rtl";
|
|
||||||
|
|
||||||
export let id: string | undefined = undefined;
|
|
||||||
let className = "";
|
|
||||||
export { className as class };
|
|
||||||
|
|
||||||
export let tooltip: string | undefined = undefined;
|
|
||||||
export let disabled = false;
|
|
||||||
|
|
||||||
let buttonRef: HTMLSelectElement;
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
onMount(() => dispatch("mount", { button: buttonRef }));
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-no-onchange -->
|
|
||||||
<select
|
|
||||||
tabindex="-1"
|
|
||||||
bind:this={buttonRef}
|
|
||||||
{id}
|
|
||||||
{disabled}
|
|
||||||
class="{className} form-select"
|
|
||||||
class:btn-day={!$pageTheme.isDark}
|
|
||||||
class:btn-night={$pageTheme.isDark}
|
|
||||||
class:rtl
|
|
||||||
title={tooltip}
|
|
||||||
on:change
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</select>
|
|
||||||
<div class="arrow" class:dark={$pageTheme.isDark} class:rtl />
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@use "sass/button-mixins" as button;
|
|
||||||
@include button.base($selector: "select", $with-hover: false);
|
|
||||||
|
|
||||||
select {
|
|
||||||
height: var(--buttons-size);
|
|
||||||
/* Long option name can create overflow */
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
/* Prevents text getting cropped on Windows */
|
|
||||||
padding: {
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
&.rtl {
|
|
||||||
direction: rtl;
|
|
||||||
/* Reversed Bootstrap values */
|
|
||||||
padding-left: 2.25rem;
|
|
||||||
padding-right: 0.75rem;
|
|
||||||
}
|
|
||||||
&.btn-day {
|
|
||||||
/* Hide default arrow for consistency */
|
|
||||||
background: var(--canvas-elevated);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
top: 0;
|
|
||||||
right: 10px;
|
|
||||||
&.rtl {
|
|
||||||
left: 10px;
|
|
||||||
}
|
|
||||||
width: 15px;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
background: button.down-arrow(black) no-repeat right;
|
|
||||||
&.dark {
|
|
||||||
background-image: button.down-arrow(white);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -3,16 +3,22 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let value: string | undefined = undefined;
|
import { createEventDispatcher } from "svelte";
|
||||||
export let selected = false;
|
|
||||||
|
import DropdownItem from "./DropdownItem.svelte";
|
||||||
|
|
||||||
|
export let disabled = false;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
let element: HTMLButtonElement;
|
||||||
|
|
||||||
|
function onSelect(): void {
|
||||||
|
if (!disabled) {
|
||||||
|
dispatch("select");
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<option class="select-option" {value} {selected}>
|
<DropdownItem {disabled} on:click={onSelect} bind:buttonRef={element}>
|
||||||
<slot />
|
<slot />
|
||||||
</option>
|
</DropdownItem>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.select-option {
|
|
||||||
background-color: var(--canvas-elevated);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
135
ts/components/SpinBox.svelte
Normal file
135
ts/components/SpinBox.svelte
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<!--
|
||||||
|
Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import IconConstrain from "./IconConstrain.svelte";
|
||||||
|
import { chevronLeft, chevronRight } from "./icons";
|
||||||
|
|
||||||
|
export let value = 1;
|
||||||
|
export let step = 1;
|
||||||
|
export let min = 1;
|
||||||
|
export let max = 9999;
|
||||||
|
|
||||||
|
const rtl: boolean = window.getComputedStyle(document.body).direction == "rtl";
|
||||||
|
|
||||||
|
let input: HTMLInputElement;
|
||||||
|
let focused = false;
|
||||||
|
|
||||||
|
function decimalPlaces(value: number) {
|
||||||
|
if (Math.floor(value) === value) return 0;
|
||||||
|
return value.toString().split(".")[1].length || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stringValue: string;
|
||||||
|
$: stringValue = value.toFixed(decimalPlaces(step));
|
||||||
|
|
||||||
|
function update(this: HTMLInputElement): void {
|
||||||
|
value = Math.min(max, Math.max(min, parseFloat(this.value)));
|
||||||
|
if (value > max) {
|
||||||
|
value = max;
|
||||||
|
} else if (value < min) {
|
||||||
|
value = min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWheel(event: WheelEvent) {
|
||||||
|
if (focused) {
|
||||||
|
value += event.deltaY < 0 ? step : -step;
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="spin-box" on:wheel={handleWheel}>
|
||||||
|
<button
|
||||||
|
class="left"
|
||||||
|
disabled={rtl ? value == max : value == min}
|
||||||
|
on:click={() => {
|
||||||
|
input.focus();
|
||||||
|
if (rtl && value < max) {
|
||||||
|
value += step;
|
||||||
|
} else if (value > min) {
|
||||||
|
value -= step;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconConstrain>
|
||||||
|
{@html chevronLeft}
|
||||||
|
</IconConstrain>
|
||||||
|
</button>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
inputmode="numeric"
|
||||||
|
{min}
|
||||||
|
{max}
|
||||||
|
{step}
|
||||||
|
value={stringValue}
|
||||||
|
bind:this={input}
|
||||||
|
on:blur={update}
|
||||||
|
on:focusin={() => (focused = true)}
|
||||||
|
on:focusout={() => (focused = false)}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="right"
|
||||||
|
disabled={rtl ? value == min : value == max}
|
||||||
|
on:click={() => {
|
||||||
|
input.focus();
|
||||||
|
if (rtl && value > min) {
|
||||||
|
value -= step;
|
||||||
|
} else if (value < max) {
|
||||||
|
value += step;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconConstrain>
|
||||||
|
{@html chevronRight}
|
||||||
|
</IconConstrain>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use "sass/button-mixins" as button;
|
||||||
|
|
||||||
|
.spin-box {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.2rem 1.5rem 0.2rem 0.75rem;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
text-align: center;
|
||||||
|
&::-webkit-inner-spin-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
button {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
@include button.base($border: false);
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
inset: 0 auto 0 0;
|
||||||
|
border-right: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
&.right {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 0 0 auto;
|
||||||
|
border-left: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -27,7 +27,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 50;
|
z-index: var(--z-index, 50);
|
||||||
|
|
||||||
background: var(--sticky-bg, var(--canvas));
|
background: var(--sticky-bg, var(--canvas));
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
|
|
@ -61,6 +61,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
export let closeOnInsideClick = false;
|
export let closeOnInsideClick = false;
|
||||||
export let keepOnKeyup = false;
|
export let keepOnKeyup = false;
|
||||||
|
export let hideArrow = false;
|
||||||
|
|
||||||
export let reference: ReferenceElement | undefined = undefined;
|
export let reference: ReferenceElement | undefined = undefined;
|
||||||
let floating: FloatingElement;
|
let floating: FloatingElement;
|
||||||
|
@ -170,13 +171,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div bind:this={floating} class="floating" use:portal={portalTarget}>
|
<div bind:this={floating} class="floating" class:show use:portal={portalTarget}>
|
||||||
{#if show}
|
{#if show}
|
||||||
<slot name="floating" />
|
<slot name="floating" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div bind:this={arrow} class="floating-arrow" hidden={!show}>
|
<div bind:this={arrow} class="floating-arrow" hidden={!show}>
|
||||||
|
{#if !hideArrow}
|
||||||
<FloatingArrow />
|
<FloatingArrow />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -188,7 +191,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
z-index: 890;
|
z-index: 890;
|
||||||
|
&.show {
|
||||||
@include elevation.elevation(8);
|
@include elevation.elevation(8);
|
||||||
|
}
|
||||||
|
|
||||||
&-arrow {
|
&-arrow {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -140,7 +140,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div bind:this={floating} class="overlay">
|
<div bind:this={floating} class="overlay" class:show>
|
||||||
{#if show}
|
{#if show}
|
||||||
<slot name="overlay" />
|
<slot name="overlay" />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -154,6 +154,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
|
&.show {
|
||||||
@include elevation.elevation(5);
|
@include elevation.elevation(5);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
8
ts/components/icons.ts
Normal file
8
ts/components/icons.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
/// <reference types="../lib/image-import" />
|
||||||
|
|
||||||
|
export { default as chevronDown } from "@mdi/svg/svg/chevron-down.svg";
|
||||||
|
export { default as chevronLeft } from "@mdi/svg/svg/chevron-left.svg";
|
||||||
|
export { default as chevronRight } from "@mdi/svg/svg/chevron-right.svg";
|
|
@ -9,7 +9,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import ButtonGroup from "../components/ButtonGroup.svelte";
|
import ButtonGroup from "../components/ButtonGroup.svelte";
|
||||||
import ButtonToolbar from "../components/ButtonToolbar.svelte";
|
import ButtonToolbar from "../components/ButtonToolbar.svelte";
|
||||||
import { modalsKey } from "../components/context-keys";
|
import { modalsKey } from "../components/context-keys";
|
||||||
import SelectButton from "../components/SelectButton.svelte";
|
import Select from "../components/Select.svelte";
|
||||||
import SelectOption from "../components/SelectOption.svelte";
|
import SelectOption from "../components/SelectOption.svelte";
|
||||||
import StickyContainer from "../components/StickyContainer.svelte";
|
import StickyContainer from "../components/StickyContainer.svelte";
|
||||||
import * as tr from "../lib/ftl";
|
import * as tr from "../lib/ftl";
|
||||||
|
@ -23,16 +23,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
const dispatchPresetChange = () => dispatch("presetchange");
|
const dispatchPresetChange = () => dispatch("presetchange");
|
||||||
|
|
||||||
|
$: {
|
||||||
|
state.setCurrentIndex(value);
|
||||||
|
dispatchPresetChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
$: options = Array.from($configList, (entry) => configLabel(entry));
|
||||||
|
$: value = $configList.find((entry) => entry.current)?.idx || 0;
|
||||||
|
|
||||||
function configLabel(entry: ConfigListEntry): string {
|
function configLabel(entry: ConfigListEntry): string {
|
||||||
const count = tr.deckConfigUsedByDecks({ decks: entry.useCount });
|
const count = tr.deckConfigUsedByDecks({ decks: entry.useCount });
|
||||||
return `${entry.name} (${count})`;
|
return `${entry.name} (${count})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function blur(event: Event): void {
|
|
||||||
state.setCurrentIndex(parseInt((event.target! as HTMLSelectElement).value));
|
|
||||||
dispatchPresetChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onAddConfig(text: string): void {
|
function onAddConfig(text: string): void {
|
||||||
const trimmed = text.trim();
|
const trimmed = text.trim();
|
||||||
if (trimmed.length) {
|
if (trimmed.length) {
|
||||||
|
@ -93,18 +96,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<StickyContainer --gutter-block="0.5rem" --sticky-borders="0 0 1px" breakpoint="sm">
|
<StickyContainer --gutter-block="0.5rem" --sticky-borders="0 0 1px" breakpoint="sm">
|
||||||
<ButtonToolbar class="justify-content-between" size={2.3} wrap={false}>
|
<ButtonToolbar class="justify-content-between" size={2.3} wrap={false}>
|
||||||
<ButtonGroup class="flex-grow-1">
|
<ButtonGroup class="flex-grow-1">
|
||||||
<SelectButton
|
<Select class="flex-grow-1" current={options[value]}>
|
||||||
class="flex-grow-1"
|
{#each options as option, idx}
|
||||||
on:change={blur}
|
<SelectOption on:select={() => (value = idx)}
|
||||||
--border-left-radius="5px"
|
>{option}
|
||||||
--border-right-radius="5px"
|
|
||||||
>
|
|
||||||
{#each $configList as entry}
|
|
||||||
<SelectOption value={String(entry.idx)} selected={entry.current}>
|
|
||||||
{configLabel(entry)}
|
|
||||||
</SelectOption>
|
</SelectOption>
|
||||||
{/each}
|
{/each}
|
||||||
</SelectButton>
|
</Select>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<SaveButton
|
<SaveButton
|
||||||
|
|
|
@ -3,39 +3,18 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
import Select from "../components/Select.svelte";
|
||||||
|
import SelectOption from "../components/SelectOption.svelte";
|
||||||
|
|
||||||
export let choices: string[];
|
export let options: string[] = [];
|
||||||
export let value: number = 0;
|
|
||||||
export let disabled: number[] = [];
|
export let disabled: number[] = [];
|
||||||
|
export let value = 0;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<select
|
<Select current={options[value]}>
|
||||||
bind:value
|
{#each options as option, idx}
|
||||||
class:nightMode={$pageTheme.isDark}
|
<SelectOption disabled={disabled.includes(idx)} on:select={() => (value = idx)}
|
||||||
class:visible-down-arrow={$pageTheme.isDark}
|
>{option}</SelectOption
|
||||||
class="enum-selector form-select"
|
|
||||||
>
|
>
|
||||||
{#each choices as choice, idx}
|
|
||||||
<option value={idx} disabled={disabled.includes(idx)}>{choice}</option>
|
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</Select>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@use "sass/night-mode" as nightmode;
|
|
||||||
@use "sass/button-mixins" as button;
|
|
||||||
|
|
||||||
.nightMode {
|
|
||||||
@include nightmode.input;
|
|
||||||
}
|
|
||||||
|
|
||||||
.enum-selector {
|
|
||||||
/* overwrite Bootstrap */
|
|
||||||
padding: 0.2rem 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.visible-down-arrow {
|
|
||||||
/* override the default down arrow */
|
|
||||||
background-image: button.down-arrow(white);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<TooltipLabel {markdownTooltip}><slot /></TooltipLabel>
|
<TooltipLabel {markdownTooltip}><slot /></TooltipLabel>
|
||||||
</Col>
|
</Col>
|
||||||
<Col --col-size={5} {breakpoint}>
|
<Col --col-size={5} {breakpoint}>
|
||||||
<EnumSelector bind:value {choices} {disabled} />
|
<EnumSelector bind:value options={choices} {disabled} />
|
||||||
<RevertButton bind:value {defaultValue} />
|
<RevertButton bind:value {defaultValue} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
@ -95,5 +95,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
.hide :global(.badge) {
|
.hide :global(.badge) {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
cursor: initial;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,11 +5,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, tick } from "svelte";
|
import { createEventDispatcher, tick } from "svelte";
|
||||||
|
|
||||||
import ButtonGroup from "../components/ButtonGroup.svelte";
|
|
||||||
import DropdownDivider from "../components/DropdownDivider.svelte";
|
import DropdownDivider from "../components/DropdownDivider.svelte";
|
||||||
import DropdownItem from "../components/DropdownItem.svelte";
|
import DropdownItem from "../components/DropdownItem.svelte";
|
||||||
|
import LabelButton from "../components/IconButton.svelte";
|
||||||
import IconButton from "../components/IconButton.svelte";
|
import IconButton from "../components/IconButton.svelte";
|
||||||
import LabelButton from "../components/LabelButton.svelte";
|
|
||||||
import Popover from "../components/Popover.svelte";
|
import Popover from "../components/Popover.svelte";
|
||||||
import Shortcut from "../components/Shortcut.svelte";
|
import Shortcut from "../components/Shortcut.svelte";
|
||||||
import WithFloating from "../components/WithFloating.svelte";
|
import WithFloating from "../components/WithFloating.svelte";
|
||||||
|
@ -64,13 +63,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
let showFloating = false;
|
let showFloating = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ButtonGroup>
|
|
||||||
<LabelButton
|
<LabelButton
|
||||||
theme="primary"
|
primary
|
||||||
on:click={() => save(false)}
|
on:click={() => save(false)}
|
||||||
tooltip={getPlatformString(saveKeyCombination)}
|
tooltip={getPlatformString(saveKeyCombination)}
|
||||||
--border-left-radius="5px">{tr.deckConfigSaveButton()}</LabelButton
|
--border-left-radius="var(--border-radius)"
|
||||||
>
|
>
|
||||||
|
<div class="save">{tr.deckConfigSaveButton()}</div>
|
||||||
|
</LabelButton>
|
||||||
<Shortcut keyCombination={saveKeyCombination} on:action={() => save(false)} />
|
<Shortcut keyCombination={saveKeyCombination} on:action={() => save(false)} />
|
||||||
|
|
||||||
<WithFloating
|
<WithFloating
|
||||||
|
@ -80,15 +80,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
on:close={() => (showFloating = false)}
|
on:close={() => (showFloating = false)}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
class="chevron"
|
||||||
slot="reference"
|
slot="reference"
|
||||||
widthMultiplier={0.5}
|
|
||||||
iconSize={120}
|
|
||||||
--border-right-radius="5px"
|
|
||||||
on:click={() => (showFloating = !showFloating)}
|
on:click={() => (showFloating = !showFloating)}
|
||||||
|
--border-right-radius="var(--border-radius)"
|
||||||
|
iconSize={80}
|
||||||
>
|
>
|
||||||
{@html chevronDown}
|
{@html chevronDown}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
<Popover slot="floating">
|
<Popover slot="floating">
|
||||||
<DropdownItem on:click={() => dispatch("add")}
|
<DropdownItem on:click={() => dispatch("add")}
|
||||||
>{tr.deckConfigAddGroup()}</DropdownItem
|
>{tr.deckConfigAddGroup()}</DropdownItem
|
||||||
|
@ -99,8 +98,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<DropdownItem on:click={() => dispatch("rename")}>
|
<DropdownItem on:click={() => dispatch("rename")}>
|
||||||
{tr.deckConfigRenameGroup()}
|
{tr.deckConfigRenameGroup()}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DropdownItem on:click={removeConfig}
|
<DropdownItem on:click={removeConfig}>{tr.deckConfigRemoveGroup()}</DropdownItem
|
||||||
>{tr.deckConfigRemoveGroup()}</DropdownItem
|
|
||||||
>
|
>
|
||||||
<DropdownDivider />
|
<DropdownDivider />
|
||||||
<DropdownItem on:click={() => save(true)}>
|
<DropdownItem on:click={() => save(true)}>
|
||||||
|
@ -108,4 +106,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</Popover>
|
</Popover>
|
||||||
</WithFloating>
|
</WithFloating>
|
||||||
</ButtonGroup>
|
|
||||||
|
<style lang="scss">
|
||||||
|
.save {
|
||||||
|
margin: 0.2rem 0.75rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<!--
|
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
-->
|
|
||||||
<script lang="ts">
|
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
|
||||||
|
|
||||||
export let value: number;
|
|
||||||
export let min = 1;
|
|
||||||
export let max = 9999;
|
|
||||||
|
|
||||||
function checkMinMax() {
|
|
||||||
if (value > max) {
|
|
||||||
value = max;
|
|
||||||
} else if (value < min) {
|
|
||||||
value = min;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
pattern="[0-9]*"
|
|
||||||
inputmode="numeric"
|
|
||||||
{min}
|
|
||||||
{max}
|
|
||||||
bind:value
|
|
||||||
class="spin-box form-control"
|
|
||||||
class:nightMode={$pageTheme.isDark}
|
|
||||||
on:blur={checkMinMax}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@use "sass/night-mode" as nightmode;
|
|
||||||
|
|
||||||
.spin-box {
|
|
||||||
/* overwrite Bootstrap */
|
|
||||||
padding: 0.2rem 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nightMode {
|
|
||||||
@include nightmode.input;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,37 +0,0 @@
|
||||||
<!--
|
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
-->
|
|
||||||
<script lang="ts">
|
|
||||||
import { pageTheme } from "../sveltelib/theme";
|
|
||||||
|
|
||||||
export let value: number;
|
|
||||||
export let min = 1;
|
|
||||||
export let max = 9999;
|
|
||||||
|
|
||||||
let stringValue: string;
|
|
||||||
$: stringValue = value.toFixed(2);
|
|
||||||
|
|
||||||
function update(this: HTMLInputElement): void {
|
|
||||||
value = Math.min(max, Math.max(min, parseFloat(this.value)));
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
class="form-control"
|
|
||||||
class:nightMode={$pageTheme.isDark}
|
|
||||||
{min}
|
|
||||||
{max}
|
|
||||||
step="0.01"
|
|
||||||
value={stringValue}
|
|
||||||
on:blur={update}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@use "sass/night-mode" as nightmode;
|
|
||||||
|
|
||||||
.nightMode {
|
|
||||||
@include nightmode.input;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -5,8 +5,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Col from "../components/Col.svelte";
|
import Col from "../components/Col.svelte";
|
||||||
import Row from "../components/Row.svelte";
|
import Row from "../components/Row.svelte";
|
||||||
|
import SpinBox from "../components/SpinBox.svelte";
|
||||||
import RevertButton from "./RevertButton.svelte";
|
import RevertButton from "./RevertButton.svelte";
|
||||||
import SpinBoxFloat from "./SpinBoxFloat.svelte";
|
|
||||||
import TooltipLabel from "./TooltipLabel.svelte";
|
import TooltipLabel from "./TooltipLabel.svelte";
|
||||||
|
|
||||||
export let value: any;
|
export let value: any;
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
<TooltipLabel {markdownTooltip}><slot /></TooltipLabel>
|
<TooltipLabel {markdownTooltip}><slot /></TooltipLabel>
|
||||||
</Col>
|
</Col>
|
||||||
<Col --col-size={5} breakpoint="sm">
|
<Col --col-size={5} breakpoint="sm">
|
||||||
<SpinBoxFloat bind:value {min} {max} />
|
<SpinBox bind:value {min} {max} step={0.01} />
|
||||||
<RevertButton bind:value {defaultValue} />
|
<RevertButton bind:value {defaultValue} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Col from "../components/Col.svelte";
|
import Col from "../components/Col.svelte";
|
||||||
import Row from "../components/Row.svelte";
|
import Row from "../components/Row.svelte";
|
||||||
|
import SpinBox from "../components/SpinBox.svelte";
|
||||||
import RevertButton from "./RevertButton.svelte";
|
import RevertButton from "./RevertButton.svelte";
|
||||||
import SpinBox from "./SpinBox.svelte";
|
|
||||||
import TooltipLabel from "./TooltipLabel.svelte";
|
import TooltipLabel from "./TooltipLabel.svelte";
|
||||||
|
|
||||||
export let value: any;
|
export let value: any;
|
||||||
|
|
|
@ -8,14 +8,15 @@ $size: var(--buttons-size);
|
||||||
$padding: 2px;
|
$padding: 2px;
|
||||||
|
|
||||||
.linkb {
|
.linkb {
|
||||||
|
@include button.base;
|
||||||
|
@include button.border-radius;
|
||||||
|
|
||||||
width: $size;
|
width: $size;
|
||||||
height: $size;
|
height: $size;
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
font-size: calc($size * 0.6);
|
font-size: calc($size * 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@include button.base($selector: ".linkb");
|
|
||||||
|
|
||||||
img.topbut {
|
img.topbut {
|
||||||
max-width: calc($size - 2 * $padding);
|
max-width: calc($size - 2 * $padding);
|
||||||
max-height: calc($size - 2 * $padding);
|
max-height: calc($size - 2 * $padding);
|
||||||
|
|
|
@ -7,4 +7,6 @@ input[type="checkbox"] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
@include button.base;
|
@include button.base;
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
><Col --col-size={4}>{basename(path)}</Col><Col --col-justify="end">
|
><Col --col-size={4}>{basename(path)}</Col><Col --col-justify="end">
|
||||||
<ButtonGroup size={2}>
|
<ButtonGroup size={2}>
|
||||||
<LabelButton
|
<LabelButton
|
||||||
theme="primary"
|
primary
|
||||||
tooltip={getPlatformString(keyCombination)}
|
tooltip={getPlatformString(keyCombination)}
|
||||||
on:click={onImport}
|
on:click={onImport}
|
||||||
--border-left-radius="5px"
|
--border-left-radius="5px"
|
||||||
|
|
|
@ -22,7 +22,6 @@ body {
|
||||||
padding-bottom: 5em;
|
padding-bottom: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
// override the default down arrow colour in <select> elements
|
html {
|
||||||
.night-mode select {
|
overflow-x: hidden;
|
||||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23FFFFFF' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
button {
|
||||||
@include button.base($with-disabled: false);
|
@include button.base($with-disabled: false, $active-class: active);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -58,6 +58,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag {
|
.tag {
|
||||||
|
@include button.base($with-active: false, $with-disabled: false);
|
||||||
|
|
||||||
font-size: var(--base-font-size);
|
font-size: var(--base-font-size);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
|
@ -81,6 +83,4 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
--border-color: var(--border-focus);
|
--border-color: var(--border-focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include button.base($with-active: false, $with-disabled: false);
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue