Centralize and use global spacing variables
This commit improves UI consistency. It also improves maintainability by
removing "magic values" in favor of standardized spacing throughout the
application.
- Adjust spacing variables to match the convention.
- Add `_spacing.scss` to define a centralized set of spacing variables, both
absolute and relative, to standardize the spacing throughout the application.
This new approach ensures a consistent spacing logic across all components and
layouts, facilitating easier maintenance and scalability of the styling codebase.
- Update various SCSS styles to utilize the new spacing variables. This change
harmonizes the spacing across different parts of the application, aligning with
the new design system's principles.
- Slightly adjust existing padding/margin/gaps for better consistency.
Other supporting changes per component:
- RatingCircle: Update style names to match convention and simplify
hacky way to inject circle width value through CSS variables. Add
tests for the new behavior and refactor existing tests for easier
extensibility.
- TheFooter: Add small gap when footer items wrap.
- HiearchicalTreeNode: Refactor variables to separate caret size clearly
from padding applied.
- App: Make padding responsive as initial behavior of v0.13.0 before
5d940b57ef.
- ModalDialog: Use responsive absolute values instead of percentage.
- HorizontalResizeSlider:
- Use `v-bind` instead of hacky way to inject SCSS values through variables.
- Remove `verticalMargin` property to simplify its styling.
- Move `src/presentation/assets/styles/components/_card.scss` closer to
components that it styles. Update structure documentation.
The centralization of spacing definitions will aid in future design
adjustments, ensuring that updates to spacing can be made swiftly and
uniformly across the application. It's a step towards a more maintainable
and scalable frontend architecture.
This commit is contained in:
@@ -25,7 +25,7 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
$gap: 0.25rem;
|
||||
$gap: $spacing-relative-x-small;
|
||||
.list {
|
||||
display: flex;
|
||||
:deep(.items) {
|
||||
|
||||
@@ -37,8 +37,10 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
.circle-rating {
|
||||
display: inline-flex;
|
||||
gap: 0.2em;
|
||||
gap: $spacing-relative-x-small;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
<template>
|
||||
<svg
|
||||
:style="{
|
||||
'--circle-stroke-width': `${circleStrokeWidthInPx}px`,
|
||||
}"
|
||||
:viewBox="viewBox"
|
||||
>
|
||||
<circle
|
||||
:cx="circleRadiusInPx"
|
||||
:cy="circleRadiusInPx"
|
||||
:r="circleRadiusWithoutStrokeInPx"
|
||||
:class="{
|
||||
filled,
|
||||
}"
|
||||
/>
|
||||
</svg>
|
||||
<span class="circle-container">
|
||||
<svg :viewBox="viewBox">
|
||||
<circle
|
||||
:cx="circleRadiusInPx"
|
||||
:cy="circleRadiusInPx"
|
||||
:r="circleRadiusWithoutStrokeInPx"
|
||||
:stroke-width="circleStrokeWidthStyleValue"
|
||||
:class="{
|
||||
filled,
|
||||
}"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -43,10 +41,13 @@ export default defineComponent({
|
||||
const height = circleDiameterInPx + circleStrokeWidthInPx;
|
||||
return `${minX} ${minY} ${width} ${height}`;
|
||||
});
|
||||
const circleStrokeWidthStyleValue = computed(() => {
|
||||
return `${circleStrokeWidthInPx}px`;
|
||||
});
|
||||
return {
|
||||
circleRadiusInPx,
|
||||
circleDiameterInPx,
|
||||
circleStrokeWidthInPx,
|
||||
circleStrokeWidthStyleValue,
|
||||
circleRadiusWithoutStrokeInPx,
|
||||
viewBox,
|
||||
};
|
||||
@@ -55,17 +56,18 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$circleColor: currentColor;
|
||||
$circleHeight: 0.8em;
|
||||
$circleStrokeWidth: var(--circle-stroke-width);
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
$circle-color: currentColor;
|
||||
$circle-height: $font-size-relative-smaller;
|
||||
|
||||
svg {
|
||||
height: $circleHeight;
|
||||
font-size: $circle-height;
|
||||
height: 1em;
|
||||
circle {
|
||||
stroke: $circleColor;
|
||||
stroke-width: $circleStrokeWidth;
|
||||
stroke: $circle-color;
|
||||
&.filled {
|
||||
fill: $circleColor;
|
||||
fill: $circle-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ export default defineComponent({
|
||||
|
||||
@mixin horizontal-stack {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
gap: $spacing-relative-small;
|
||||
}
|
||||
|
||||
@mixin apply-icon-color($color) {
|
||||
|
||||
@@ -55,7 +55,7 @@ export default defineComponent({
|
||||
|
||||
@mixin horizontal-stack {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
gap: $spacing-relative-small;
|
||||
}
|
||||
|
||||
@mixin apply-icon-color($color) {
|
||||
|
||||
@@ -70,8 +70,6 @@ export default defineComponent({
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
@use 'sass:math';
|
||||
|
||||
$spacing-small: math.div($base-spacing, 2);
|
||||
|
||||
@mixin center-middle-flex-item {
|
||||
&:first-child, &:last-child {
|
||||
flex-grow: 1;
|
||||
@@ -87,12 +85,12 @@ $responsive-alignment-breakpoint: $media-screen-medium-width;
|
||||
.scripts-menu {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: $base-spacing;
|
||||
row-gap: $base-spacing;
|
||||
column-gap: $spacing-relative-medium;
|
||||
row-gap: $spacing-relative-small;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin-left: $spacing-small;
|
||||
margin-right: $spacing-small;
|
||||
margin-left: $spacing-absolute-small;
|
||||
margin-right: $spacing-absolute-small;
|
||||
@media screen and (max-width: $responsive-alignment-breakpoint) {
|
||||
justify-content: space-around;
|
||||
}
|
||||
@@ -106,7 +104,7 @@ $responsive-alignment-breakpoint: $media-screen-medium-width;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
row-gap: 0.5em;
|
||||
row-gap: $spacing-relative-x-small;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="slider"
|
||||
:style="{
|
||||
'--vertical-margin': verticalMargin,
|
||||
'--first-min-width': firstMinWidth,
|
||||
'--first-initial-width': firstInitialWidth,
|
||||
'--second-min-width': secondMinWidth,
|
||||
}"
|
||||
>
|
||||
<div class="slider">
|
||||
<div ref="firstElement" class="first">
|
||||
<slot name="first" />
|
||||
</div>
|
||||
@@ -27,10 +19,6 @@ export default defineComponent({
|
||||
SliderHandle,
|
||||
},
|
||||
props: {
|
||||
verticalMargin: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
firstMinWidth: {
|
||||
type: String,
|
||||
required: true,
|
||||
@@ -71,21 +59,18 @@ export default defineComponent({
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.first {
|
||||
min-width: var(--first-min-width);
|
||||
width: var(--first-initial-width);
|
||||
min-width: v-bind(firstMinWidth);
|
||||
width: v-bind(firstInitialWidth);
|
||||
}
|
||||
.second {
|
||||
flex: 1;
|
||||
min-width: var(--second-min-width);
|
||||
min-width: v-bind(secondMinWidth);
|
||||
}
|
||||
@media screen and (max-width: $media-vertical-view-breakpoint) {
|
||||
flex-direction: column;
|
||||
.first {
|
||||
width: auto !important;
|
||||
}
|
||||
.second {
|
||||
margin-top: var(--vertical-margin);
|
||||
}
|
||||
.handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ $cursor : v-bind(cursorCssValue);
|
||||
.icon {
|
||||
color: $color;
|
||||
}
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
margin-right: $spacing-absolute-small;
|
||||
margin-left: $spacing-absolute-small;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
<div class="script-area">
|
||||
<TheScriptsMenu @view-changed="currentView = $event" />
|
||||
<HorizontalResizeSlider
|
||||
class="row"
|
||||
vertical-margin="15px"
|
||||
class="horizontal-slider"
|
||||
first-initial-width="55%"
|
||||
first-min-width="20%"
|
||||
second-min-width="20%"
|
||||
@@ -42,9 +41,17 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
.script-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: $spacing-absolute-medium;
|
||||
}
|
||||
|
||||
.horizontal-slider {
|
||||
// Add row gap between lines on mobile (smaller screens)
|
||||
// when the slider turns into rows.
|
||||
row-gap: $spacing-absolute-large;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -125,6 +125,7 @@ function isClickable(element: Element) {
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
@use "./card-gap" as *;
|
||||
|
||||
.cards {
|
||||
display: flex;
|
||||
@@ -135,7 +136,7 @@ function isClickable(element: Element) {
|
||||
It ensures that there's room to grow, so the animation is shown without overflowing
|
||||
with scrollbars.
|
||||
*/
|
||||
padding: 10px;
|
||||
padding: $spacing-absolute-medium;
|
||||
}
|
||||
|
||||
.error {
|
||||
|
||||
@@ -138,9 +138,10 @@ export default defineComponent({
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
@use "./card-gap" as *;
|
||||
|
||||
$card-inner-padding : 30px;
|
||||
$expanded-margin-top : 30px;
|
||||
$card-inner-padding : $spacing-absolute-xx-large;
|
||||
$expanded-margin-top : $spacing-absolute-xx-large;
|
||||
$card-horizontal-gap : $card-gap;
|
||||
|
||||
.card {
|
||||
@@ -178,13 +179,13 @@ $card-horizontal-gap : $card-gap;
|
||||
.card__inner__selection_indicator {
|
||||
height: $card-inner-padding;
|
||||
margin-right: -$card-inner-padding;
|
||||
padding-right: 10px;
|
||||
padding-right: $spacing-absolute-medium;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.card__inner__expand-icon {
|
||||
width: 100%;
|
||||
margin-top: .25em;
|
||||
margin-top: $spacing-relative-x-small;
|
||||
vertical-align: middle;
|
||||
font-size: $font-size-absolute-normal;
|
||||
}
|
||||
@@ -209,7 +210,7 @@ $card-horizontal-gap : $card-gap;
|
||||
.card__expander__close-button {
|
||||
font-size: $font-size-absolute-large;
|
||||
align-self: flex-end;
|
||||
margin-right: 0.25em;
|
||||
margin-right: $spacing-absolute-small;
|
||||
@include clickable;
|
||||
color: $color-primary-light;
|
||||
@include hover-or-touch {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
$card-gap: $spacing-absolute-large;
|
||||
@@ -128,10 +128,7 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
$margin-inner: 4px;
|
||||
|
||||
.scripts-view {
|
||||
margin-top: $margin-inner;
|
||||
@media screen and (min-width: $media-vertical-view-breakpoint) {
|
||||
// so the current code is always visible
|
||||
overflow: auto;
|
||||
@@ -143,16 +140,17 @@ $margin-inner: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: $color-scripts-bg;
|
||||
padding-top: $spacing-absolute-large;
|
||||
padding-bottom:$spacing-absolute-large;
|
||||
.search__query {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: 1em;
|
||||
color: $color-primary-light;
|
||||
.search__query__close-button {
|
||||
font-size: $font-size-absolute-large;
|
||||
margin-left: 0.25rem;
|
||||
margin-left: $spacing-relative-x-small;
|
||||
}
|
||||
}
|
||||
.search-no-matches {
|
||||
@@ -161,11 +159,9 @@ $margin-inner: 4px;
|
||||
word-break:break-word;
|
||||
color: $color-on-primary;
|
||||
font-size: $font-size-absolute-large;
|
||||
padding:10px;
|
||||
padding: $spacing-absolute-medium;
|
||||
text-align:center;
|
||||
> div {
|
||||
padding-bottom:13px;
|
||||
}
|
||||
gap: $spacing-relative-small;
|
||||
a {
|
||||
color: $color-primary;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export default defineComponent({
|
||||
flex: 1; // Expands the container to fill available horizontal space, enabling alignment of child items.
|
||||
max-width: 100%; // Prevents horizontal expansion of inner content (e.g., when a code block is shown)
|
||||
*:not(:first-child) {
|
||||
margin-left: 5px;
|
||||
margin-left: $spacing-absolute-small;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
@@ -80,10 +80,10 @@ export default defineComponent({
|
||||
}
|
||||
.docs {
|
||||
background: $color-primary-darkest;
|
||||
margin-top: 0.25em;
|
||||
margin-top: $spacing-relative-x-small;
|
||||
color: $color-on-primary;
|
||||
text-transform: none;
|
||||
padding: 0.5em;
|
||||
padding: $spacing-absolute-medium;
|
||||
&-collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export default defineComponent({
|
||||
flex-wrap: wrap;
|
||||
|
||||
.node-content-item:not(:first-child) {
|
||||
margin-left: 5px;
|
||||
margin-left: $spacing-relative-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<ToggleSwitch
|
||||
v-model="isReverted"
|
||||
:stop-click-propagation="true"
|
||||
:label="'Revert'"
|
||||
label="Revert"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -83,12 +83,12 @@ $color-text-unchecked : $color-on-primary;
|
||||
$color-text-checked : $color-on-secondary;
|
||||
$color-bg-unchecked : $color-primary;
|
||||
$color-bg-checked : $color-secondary;
|
||||
$padding-horizontal : calc($font-size * 0.4);
|
||||
$padding-vertical : calc($font-size * 0.3);
|
||||
$padding-horizontal : $spacing-relative-small;
|
||||
$padding-vertical : $spacing-absolute-small;
|
||||
$size-height : calc($font-size + ($padding-vertical * 2));
|
||||
$size-circle : math.div($size-height * 2, 3);
|
||||
$size-circle : calc($size-height * 2/3);
|
||||
|
||||
$gap-between-circle-and-text : 0.25em;
|
||||
$gap-between-circle-and-text : $spacing-relative-x-small;
|
||||
|
||||
@mixin locateNearCircle($direction: 'left') {
|
||||
$circle-width: calc(#{$size-circle} + #{$padding-horizontal});
|
||||
|
||||
@@ -73,7 +73,8 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
$padding: 20px;
|
||||
$padding-horizontal : $spacing-absolute-large;
|
||||
$padding-vertical : $spacing-absolute-x-large;
|
||||
|
||||
.scripts-tree-container {
|
||||
display: flex; // We could provide `block`, but `flex` is more versatile.
|
||||
@@ -84,11 +85,11 @@ $padding: 20px;
|
||||
|
||||
flex: 1; // Expands the container to fill available horizontal space, enabling alignment of child items.
|
||||
|
||||
padding-bottom: $padding;
|
||||
padding-left: $padding;
|
||||
padding-right: $padding;
|
||||
padding-bottom: $padding-vertical;
|
||||
padding-left: $padding-horizontal;
|
||||
padding-right: $padding-horizontal;
|
||||
&.top-padding {
|
||||
padding-top: $padding;
|
||||
padding-top: $padding-vertical;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:tree-root="treeRoot"
|
||||
>
|
||||
<div
|
||||
class="expand-collapse-arrow"
|
||||
class="expand-collapse-caret"
|
||||
:class="{
|
||||
expanded: isExpanded,
|
||||
'has-children': hasChildren,
|
||||
@@ -141,10 +141,13 @@ export default defineComponent({
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.expand-collapse-arrow {
|
||||
.expand-collapse-caret {
|
||||
$caret-size: 24px;
|
||||
$padding-right: $spacing-absolute-small;
|
||||
|
||||
flex-shrink: 0;
|
||||
height: 30px;
|
||||
margin-left: 30px;
|
||||
height: $caret-size;
|
||||
margin-left: $caret-size + $padding-right;
|
||||
width: 0;
|
||||
|
||||
@include clickable;
|
||||
@@ -157,25 +160,32 @@ export default defineComponent({
|
||||
|
||||
&.has-children {
|
||||
margin-left: 0;
|
||||
width: 30px;
|
||||
width: $caret-size + $padding-right;
|
||||
position: relative;
|
||||
|
||||
$caret-dimension: $caret-size * 0.375;
|
||||
$caret-stroke-width: 1.5px;
|
||||
&:after {
|
||||
border: 1.5px solid $color-node-arrow;
|
||||
border: $caret-stroke-width solid $color-node-arrow;
|
||||
position: absolute;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
left: 9px;
|
||||
left: $caret-dimension;
|
||||
top: 50%;
|
||||
height: 9px;
|
||||
width: 9px;
|
||||
transform: rotate(-45deg) translateY(-50%) translateX(0);
|
||||
height: $caret-dimension;
|
||||
width: $caret-dimension;
|
||||
transform:
|
||||
rotate(-45deg)
|
||||
translateY(-50%)
|
||||
translateX($caret-dimension * 0.2);
|
||||
transition: transform .25s;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
&.expanded:after {
|
||||
transform: rotate(45deg) translateY(-50%) translateX(-5px);
|
||||
transform:
|
||||
rotate(45deg)
|
||||
translateY(-50%)
|
||||
translateX($caret-dimension * -0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,18 +76,18 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
.node {
|
||||
margin-bottom: 3px;
|
||||
margin-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
padding-top: 3px;
|
||||
padding-right: 6px;
|
||||
margin-bottom: $spacing-absolute-xx-small;
|
||||
margin-top: $spacing-absolute-xx-small;
|
||||
padding-bottom: $spacing-absolute-xx-small;
|
||||
padding-top: $spacing-absolute-xx-small;
|
||||
padding-right: $spacing-absolute-small;
|
||||
box-sizing: border-box;
|
||||
|
||||
.content {
|
||||
display: flex; // We could provide `block`, but `flex` is more versatile.
|
||||
color: $color-node-fg;
|
||||
padding-left: 9px;
|
||||
padding-right: 6px;
|
||||
padding-left: $spacing-relative-small;
|
||||
padding-right: $spacing-absolute-x-small;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user