From 7d5562d2561fb7357326457a44f42e7170477a8d Mon Sep 17 00:00:00 2001 From: Untone Date: Thu, 3 Oct 2024 12:08:17 +0300 Subject: [PATCH] .. --- src/lib/createTooltip.ts | 80 +++++++++++++++++++++ src/styles/README.md | 65 ++++++++++++++++++ src/styles/_grid.scss | 145 +++++++++++++++++++++++++++++++++++++++ src/styles/_inject.scss | 2 + src/styles/_vars.scss | 30 ++++++++ 5 files changed, 322 insertions(+) create mode 100644 src/lib/createTooltip.ts create mode 100644 src/styles/README.md create mode 100644 src/styles/_grid.scss create mode 100644 src/styles/_inject.scss create mode 100644 src/styles/_vars.scss diff --git a/src/lib/createTooltip.ts b/src/lib/createTooltip.ts new file mode 100644 index 00000000..b09307e8 --- /dev/null +++ b/src/lib/createTooltip.ts @@ -0,0 +1,80 @@ +export function createTooltip(referenceElement?: Element, tooltipElement?: HTMLElement, options = {}) { + const defaultOptions = { + placement: 'top', + offset: [0, 8] + } + const config = { ...defaultOptions, ...options } + + function updatePosition() { + if (!(referenceElement && tooltipElement)) return + + const rect = referenceElement.getBoundingClientRect() + const tooltipRect = tooltipElement.getBoundingClientRect() + const offsetX = config.offset[0] + const offsetY = config.offset[1] + + let top = 0 + let left = 0 + + switch (config.placement) { + case 'top': { + top = rect.top - tooltipRect.height - offsetY + left = rect.left + (rect.width - tooltipRect.width) / 2 + offsetX + break + } + case 'bottom': { + top = rect.bottom + offsetY + left = rect.left + (rect.width - tooltipRect.width) / 2 + offsetX + break + } + case 'left': { + top = rect.top + (rect.height - tooltipRect.height) / 2 + offsetY + left = rect.left - tooltipRect.width - offsetX + break + } + case 'right': { + top = rect.top + (rect.height - tooltipRect.height) / 2 + offsetY + left = rect.right + offsetX + break + } + default: { + top = rect.top - tooltipRect.height - offsetY + left = rect.left + (rect.width - tooltipRect.width) / 2 + offsetX + } + } + + tooltipElement.style.position = 'absolute' + tooltipElement.style.top = `${top}px` + tooltipElement.style.left = `${left}px` + } + + function showTooltip() { + if (tooltipElement) tooltipElement.style.visibility = 'visible' + updatePosition() + } + + function hideTooltip() { + if (tooltipElement) tooltipElement.style.visibility = 'hidden' + } + + referenceElement?.addEventListener('mouseenter', showTooltip) + referenceElement?.addEventListener('mouseleave', hideTooltip) + window.addEventListener('resize', updatePosition) + + return { + update: updatePosition, + destroy() { + referenceElement?.removeEventListener('mouseenter', showTooltip) + referenceElement?.removeEventListener('mouseleave', hideTooltip) + window.removeEventListener('resize', updatePosition) + } + } +} + +// Usage example +const referenceElement = document.querySelector('#reference') +const tooltipElement = document.querySelector('#tooltip') +createTooltip(referenceElement as HTMLElement, tooltipElement as HTMLElement, { + placement: 'top', + offset: [0, 8] +}) diff --git a/src/styles/README.md b/src/styles/README.md new file mode 100644 index 00000000..c800769e --- /dev/null +++ b/src/styles/README.md @@ -0,0 +1,65 @@ +# _grid.scss - a Minimalistic Bootstrap-Compatible Grid System + +This grid system is a lightweight alternative to Bootstrap's grid, providing essential features for responsive design. It includes a set of SCSS mixins and classes to create flexible layouts. + +## Supported Classes in _grid.scss + +### Container + +- **`.container`**: Creates a fixed-width container and centers it on the page. +- **`.container-fluid`**: Creates a full-width container that spans the entire width of the viewport. + +### Row + +- **`.row`**: Creates a flexbox container for columns, with negative margins to offset column padding. + +### Columns + +- **`.col-xx-#`**: Defines the width of a column for a specific breakpoint (`xx` can be `xs`, `sm`, `md`, `lg`, `xl`, `xxl`). Replace `#` with a number from 1 to 24 (based on `$grid-columns`). + +### Offsets + +- **`.offset-xx-#`**: Adds left margin to a column, effectively moving it to the right by the specified number of columns. Replace `xx` with the breakpoint and `#` with the number of columns to offset. + +## Mixins + +### `media-breakpoint-up($breakpoint)` + +Applies styles at a minimum width of the specified breakpoint. + +### `media-breakpoint-down($breakpoint)` + +Applies styles at a maximum width of the specified breakpoint. + +### `media-breakpoint-between($lower, $upper)` + +Applies styles between two breakpoints. + +### `make-container($max-widths, $gutter)` + +Creates a container with specified maximum widths and gutter. + +### `make-row($gutter)` + +Creates a flexbox row with specified gutter. + +### `make-col($size, $columns)` + +Defines a column with a specific size and total number of columns. + +### `make-col-offset($size, $columns)` + +Offsets a column by a specific size. + +### `row-cols($count)` + +Sets the number of columns in a row, each taking an equal width. + +## Customization + +You can customize the grid system by modifying the variables in `_globals.scss`: + +- **`$grid-columns`**: Total number of columns in the grid. +- **`$grid-gutter-width`**: Width of the gutter between columns. +- **`$grid-breakpoints`**: Map of breakpoints for responsive design. +- **`$container-max-widths`**: Maximum widths for containers at each breakpoint. diff --git a/src/styles/_grid.scss b/src/styles/_grid.scss new file mode 100644 index 00000000..dd9fe83a --- /dev/null +++ b/src/styles/_grid.scss @@ -0,0 +1,145 @@ +// Миксин для media-breakpoint-up +@mixin media-breakpoint-up($breakpoint, $breakpoints: $grid-breakpoints) { + $min-width: map-get($breakpoints, $breakpoint); + + @if $min-width { + @media (min-width: #{$min-width}) { + @content; + } + } @else { + @warn "Нет валидного брейкпоинта для '#{$breakpoint}'."; + } +} + +// Миксин для media-breakpoint-down +@mixin media-breakpoint-down($breakpoint, $breakpoints: $grid-breakpoints) { + $max-width: map-get($breakpoints, $breakpoint) - 0.02px; + + @if $max-width { + @media (max-width: #{$max-width}) { + @content; + } + } @else { + @warn "Нет валидного брейкпоинта для '#{$breakpoint}'."; + } +} + +// Миксин для media-breakpoint-between +@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { + $min-width: map-get($breakpoints, $lower); + $max-width: map-get($breakpoints, $upper) - 0.02px; + + @if $min-width and $max-width { + @media (min-width: #{$min-width}) and (max-width: #{$max-width}) { + @content; + } + } @else { + @warn "Нет валидных брейкпоинтов для '#{$lower}' или '#{$upper}'."; + } +} + +// Миксин make-container +@mixin make-container($max-widths: $container-max-widths, $gutter: $grid-gutter-width) { + width: 100%; + padding-right: $gutter; + padding-left: $gutter; + margin-right: auto; + margin-left: auto; + + @each $breakpoint, $max-width in $max-widths { + @include media-breakpoint-up($breakpoint, $grid-breakpoints) { + max-width: #{$max-width}; + } + } +} + +// Миксин make-row +@mixin make-row($gutter: $grid-gutter-width) { + --gutter-x: #{$gutter}; + --gutter-y: 0; + + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--gutter-y)); + margin-right: calc(-0.5 * var(--gutter-x)); + margin-left: calc(-0.5 * var(--gutter-x)); +} + +// Миксин make-col-ready +@mixin make-col-ready() { + box-sizing: border-box; + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--gutter-x) * 0.5); + padding-left: calc(var(--gutter-x) * 0.5); + margin-top: var(--gutter-y); +} + +// Миксин make-col +@mixin make-col($size: false, $columns: $grid-columns) { + @if $size { + flex: 0 0 auto; + width: calc(100% * #{calc($size / $columns)}); + } @else { + flex: 1 1 0; + max-width: 100%; + } +} + +// Миксин make-col-auto +@mixin make-col-auto() { + flex: 0 0 auto; + width: auto; +} + +// Миксин make-col-offset +@mixin make-col-offset($size, $columns: $grid-columns) { + $num: calc($size / $columns); + + margin-left: if($num == 0, 0, calc(100% * #{$num})); +} + +// Миксин row-cols +@mixin row-cols($count) { + > * { + flex: 0 0 auto; + width: 100% / $count; + } +} + +// Миксин make-grid-columns +@mixin make-grid-columns($columns: $grid-columns, $breakpoints: $grid-breakpoints) { + @each $breakpoint, $value in $breakpoints { + $infix: if($breakpoint == 'xs', '', "-#{$breakpoint}"); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @include make-col($i, $columns); + } + + .offset#{$infix}-#{$i} { + @include make-col-offset($i, $columns); + } + } + } + } +} + +// Генерация классов контейнера и ряда +.container, +.container-fluid { + @include make-container($container-max-widths, $grid-gutter-width); +} + +.row { + @include make-row; + + > * { + @include make-col-ready; + } +} + +// Генерация классов столбцов и смещений +@include make-grid-columns($grid-columns, $grid-breakpoints); \ No newline at end of file diff --git a/src/styles/_inject.scss b/src/styles/_inject.scss new file mode 100644 index 00000000..771ea69c --- /dev/null +++ b/src/styles/_inject.scss @@ -0,0 +1,2 @@ +@import 'vars'; +@import 'grid'; diff --git a/src/styles/_vars.scss b/src/styles/_vars.scss new file mode 100644 index 00000000..dc4616fd --- /dev/null +++ b/src/styles/_vars.scss @@ -0,0 +1,30 @@ +$include-column-box-sizing: true !default; +$rfs-breakpoint: 1460px !default; +$rfs-base-value: 1.6rem !default; +$rfs-rem-value: 10 !default; +$grid-columns: 24; +$grid-gutter-width: 4rem !default; +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1400px, +) !default; +$default-color: #141414; +$link-color: #2638d9; +$container-padding-x: $grid-gutter-width * 0.5 !default; + +// Additional variables needed +$container-max-widths: $grid-breakpoints; +$gutters: ( + 0: 0, + 1: 0.25rem, + 2: 0.5rem, + 3: 1rem, + 4: 1.5rem, + 5: 3rem +) !default; +$grid-row-columns: 6 !default; +$prefix: '' !default;