diff --git a/modules/index.ts b/modules/index.ts index 5e53680..d5c8d27 100644 --- a/modules/index.ts +++ b/modules/index.ts @@ -1,4 +1,5 @@ export * from './nuc_api' +export * from './nuc_animations' export * from './nuc_auth' export * from './nuc_charts' export * from './nuc_colors' diff --git a/modules/nuc_animations/README.md b/modules/nuc_animations/README.md new file mode 100644 index 0000000..dccc333 --- /dev/null +++ b/modules/nuc_animations/README.md @@ -0,0 +1,9 @@ +#   nuc_animations + +Module that contains animations functions. + +
+ +

    Contributors


+ + diff --git a/modules/nuc_animations/_index.scss b/modules/nuc_animations/_index.scss new file mode 100644 index 0000000..ee90acc --- /dev/null +++ b/modules/nuc_animations/_index.scss @@ -0,0 +1 @@ +@import 'caterpillar', 'fade', 'rotate', 'shine'; diff --git a/modules/nuc_animations/caterpillar/_index.scss b/modules/nuc_animations/caterpillar/_index.scss new file mode 100644 index 0000000..4e081d2 --- /dev/null +++ b/modules/nuc_animations/caterpillar/_index.scss @@ -0,0 +1,47 @@ +@import 'keyframes', 'mixins', 'properties'; + +.caterpillar, +%caterpillar { + background: transparent !important; + border: 0 !important; + outline: #ffffff30 1px solid !important; + backdrop-filter: blur(0.5em); + border-radius: 0 !important; + z-index: 1; + overflow: visible; + color: white !important; + text-decoration: none; + + img { + position: relative; + top: -1px; + width: 20px; + height: 20px; + fill: white !important; + } + + &::before { + content: ''; + position: absolute; + inset: -1px; + border: 2px solid transparent !important; + border-image: conic-gradient( + from var(--angle), + #10b981 0deg 80deg, + transparent 60deg 200deg + ) + 1 stretch !important; + animation: rotate 4s linear infinite; + opacity: 0; + transition: opacity 0.3s; + } + + &:hover { + background: #ffffff09 !important; + + &::before { + isolation: isolate; + opacity: 1; + } + } +} diff --git a/modules/nuc_animations/caterpillar/_keyframes.scss b/modules/nuc_animations/caterpillar/_keyframes.scss new file mode 100644 index 0000000..0d4a9db --- /dev/null +++ b/modules/nuc_animations/caterpillar/_keyframes.scss @@ -0,0 +1,5 @@ +@keyframes rotate { + to { + --angle: 360deg; + } +} diff --git a/modules/nuc_animations/caterpillar/_mixins.scss b/modules/nuc_animations/caterpillar/_mixins.scss new file mode 100644 index 0000000..9656514 --- /dev/null +++ b/modules/nuc_animations/caterpillar/_mixins.scss @@ -0,0 +1,41 @@ +@mixin caterpillar { + backdrop-filter: blur(0.5em); + border-radius: 0 !important; + z-index: 1; + overflow: visible; + color: white !important; + text-decoration: none; + + img { + position: relative; + top: -1px; + width: 20px; + height: 20px; + fill: white !important; + } + + &::before { + content: ''; + position: absolute; + inset: -1px; + border: 2px solid transparent !important; + border-image: conic-gradient( + from var(--angle), + #10b981 0deg 20deg, + transparent 20deg 200deg + ) + 1 stretch !important; + animation: rotate 4s linear infinite; + opacity: 0; + transition: opacity 0.3s; + } + + &:hover { + background: #ffffff09 !important; + + &::before { + isolation: isolate; + opacity: 1; + } + } +} diff --git a/modules/nuc_animations/caterpillar/_properties.scss b/modules/nuc_animations/caterpillar/_properties.scss new file mode 100644 index 0000000..34feeda --- /dev/null +++ b/modules/nuc_animations/caterpillar/_properties.scss @@ -0,0 +1,11 @@ +@property --opacity { + syntax: ''; + initial-value: 0.5; + inherits: false; +} + +@property --angle { + syntax: ''; + initial-value: 0deg; + inherits: false; +} diff --git a/modules/nuc_animations/config.json b/modules/nuc_animations/config.json new file mode 100644 index 0000000..e515c41 --- /dev/null +++ b/modules/nuc_animations/config.json @@ -0,0 +1,8 @@ +{ + "name": "nuc_animations", + "description": "Module that contains animation functions.", + "version": "0.3.1", + "category": "core", + "installed": true, + "enabled": true +} diff --git a/modules/nuc_animations/fade/_index.scss b/modules/nuc_animations/fade/_index.scss new file mode 100644 index 0000000..71ccacc --- /dev/null +++ b/modules/nuc_animations/fade/_index.scss @@ -0,0 +1,12 @@ +@import 'keyframes'; + +%fade-in, +.fade-in { + animation: fade-in 0.3s ease-in forwards; +} + +%fade-out, +.fade-out { + animation: fade-out 0.3s ease-in forwards; + opacity: 0; +} diff --git a/modules/nuc_animations/fade/_keyframes.scss b/modules/nuc_animations/fade/_keyframes.scss new file mode 100644 index 0000000..5cfd80c --- /dev/null +++ b/modules/nuc_animations/fade/_keyframes.scss @@ -0,0 +1,19 @@ +@keyframes fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} diff --git a/modules/nuc_animations/hexagons/_index.scss b/modules/nuc_animations/hexagons/_index.scss new file mode 100644 index 0000000..2997f7d --- /dev/null +++ b/modules/nuc_animations/hexagons/_index.scss @@ -0,0 +1,32 @@ +.hexagon-rows-container { + width: 100%; + height: 100%; + position: absolute; + inset: 0; + overflow: hidden; + + .hexagon-row-container { + position: relative; + top: 30px; + margin-top: -13px; + + .hexagon-container { + display: flex; + gap: 2px; + + svg { + height: 48px; + overflow: visible; + + polygon { + transition: all 500ms ease-in; + } + } + + &.n2 { + margin-top: -13px; + margin-left: -20px; + } + } + } +} diff --git a/modules/nuc_animations/hexagons/index.ts b/modules/nuc_animations/hexagons/index.ts new file mode 100644 index 0000000..6bb7a16 --- /dev/null +++ b/modules/nuc_animations/hexagons/index.ts @@ -0,0 +1 @@ +export { NucAnimationHexagons } from './index.tsx' diff --git a/modules/nuc_animations/hexagons/index.tsx b/modules/nuc_animations/hexagons/index.tsx new file mode 100644 index 0000000..d93326a --- /dev/null +++ b/modules/nuc_animations/hexagons/index.tsx @@ -0,0 +1,78 @@ +'use client' + +import type { CSSProperties, JSX } from 'react' +import React, { useEffect, useRef, useState } from 'react' + +import './_index.scss' + +import type { HexagonPatternsType } from './types' +import { getHexagonPoints, updateImagesPerRow } from './utils' +import { PATTERN_UPDATE_INTERVAL } from './variables' + +export function NucAnimationHexagons(): JSX.Element { + const containerRef = useRef(null) + const [hexagonRows, setHexagonRows] = useState([]) + + useEffect(() => { + updateImagesPerRow( + containerRef.current, + () => undefined, + () => undefined, + setHexagonRows + ) + + const interval = setInterval(() => { + requestAnimationFrame(() => { + updateImagesPerRow( + containerRef.current, + () => undefined, + () => undefined, + setHexagonRows + ) + }) + }, PATTERN_UPDATE_INTERVAL) + + return () => { + clearInterval(interval) + } + }, []) + + return ( +
+ {hexagonRows.map((row, rowIndex) => ( +
+ {['hexagon-container n1', 'hexagon-container n2'].map( + (containerClass, containerIndex) => ( +
+ + {row[containerIndex].map((opacity, imgIndex) => ( + + ))} + +
+ ) + )} +
+ ))} +
+ ) +} diff --git a/modules/nuc_animations/hexagons/types/index.ts b/modules/nuc_animations/hexagons/types/index.ts new file mode 100644 index 0000000..6b8785a --- /dev/null +++ b/modules/nuc_animations/hexagons/types/index.ts @@ -0,0 +1,2 @@ +export * from './interfaces' +export * from './variables' diff --git a/modules/nuc_animations/hexagons/types/interfaces.ts b/modules/nuc_animations/hexagons/types/interfaces.ts new file mode 100644 index 0000000..d7863e9 --- /dev/null +++ b/modules/nuc_animations/hexagons/types/interfaces.ts @@ -0,0 +1,8 @@ +export interface HexagonConfigInterface { + width: number + height: number + containerWidth: number + containerHeight: number + imagesPerRow: number + totalRows: number +} diff --git a/modules/nuc_animations/hexagons/types/variables.ts b/modules/nuc_animations/hexagons/types/variables.ts new file mode 100644 index 0000000..53c52a6 --- /dev/null +++ b/modules/nuc_animations/hexagons/types/variables.ts @@ -0,0 +1,2 @@ +export type HexagonRowType = number[][] +export type HexagonPatternsType = number[][][] diff --git a/modules/nuc_animations/hexagons/utils/calculate_dimensions.ts b/modules/nuc_animations/hexagons/utils/calculate_dimensions.ts new file mode 100644 index 0000000..50d4b5b --- /dev/null +++ b/modules/nuc_animations/hexagons/utils/calculate_dimensions.ts @@ -0,0 +1,28 @@ +import type { HexagonConfigInterface } from '../types' +import { + HEXAGON_HEIGHT, + HEXAGON_OVERLAP_FACTOR, + HEXAGON_WIDTH, + HEXAGON_WIDTH_FACTOR, +} from '../variables' + +export function calculateDimensions( + containerWidth: number, + containerHeight: number +): HexagonConfigInterface { + const calculatedImages: number = Math.ceil( + containerWidth / (HEXAGON_WIDTH / HEXAGON_WIDTH_FACTOR) + ) + const calculatedRows: number = Math.ceil( + containerHeight / (HEXAGON_HEIGHT * HEXAGON_OVERLAP_FACTOR) + ) + + return { + width: HEXAGON_WIDTH, + height: HEXAGON_HEIGHT, + containerWidth, + containerHeight, + imagesPerRow: calculatedImages, + totalRows: calculatedRows, + } +} diff --git a/modules/nuc_animations/hexagons/utils/generate_row_pattern.ts b/modules/nuc_animations/hexagons/utils/generate_row_pattern.ts new file mode 100644 index 0000000..8409180 --- /dev/null +++ b/modules/nuc_animations/hexagons/utils/generate_row_pattern.ts @@ -0,0 +1,22 @@ +import type { HexagonRowType } from '../types' + +export function generateRowPattern( + rowIndex: number, + totalImages: number, + totalRows: number +): HexagonRowType { + const onesCount = Math.ceil((totalImages * (rowIndex + 1)) / (totalRows * 2)) + const pattern = new Array(totalImages).fill(0) + + let placedOnes = 0 + while (placedOnes < onesCount) { + const randomIndex = Math.floor(Math.random() * totalImages) + if (pattern[randomIndex] === 0) { + pattern[randomIndex] = 1 + placedOnes++ + } + } + + const half = Math.floor(totalImages / 2) + return [pattern.slice(0, half), pattern.slice(half)] +} diff --git a/modules/nuc_animations/hexagons/utils/get_hexagon_points.ts b/modules/nuc_animations/hexagons/utils/get_hexagon_points.ts new file mode 100644 index 0000000..e8c5c3a --- /dev/null +++ b/modules/nuc_animations/hexagons/utils/get_hexagon_points.ts @@ -0,0 +1,6 @@ +export function getHexagonPoints(cx: number, cy: number, r: number): string { + return Array.from({ length: 6 }, (_, i) => { + const angle = (Math.PI / 3) * i - Math.PI / 6 + return [cx + r * Math.cos(angle), cy + r * Math.sin(angle)].join(',') + }).join(' ') +} diff --git a/modules/nuc_animations/hexagons/utils/index.ts b/modules/nuc_animations/hexagons/utils/index.ts new file mode 100644 index 0000000..f7ac0b0 --- /dev/null +++ b/modules/nuc_animations/hexagons/utils/index.ts @@ -0,0 +1,5 @@ +export * from './calculate_dimensions' +export * from './generate_row_pattern' +export * from './get_hexagon_points' +export * from './update_hexagon_patterns' +export * from './update_images_per_row' diff --git a/modules/nuc_animations/hexagons/utils/update_hexagon_patterns.ts b/modules/nuc_animations/hexagons/utils/update_hexagon_patterns.ts new file mode 100644 index 0000000..939f189 --- /dev/null +++ b/modules/nuc_animations/hexagons/utils/update_hexagon_patterns.ts @@ -0,0 +1,13 @@ +import { generateRowPattern } from '.' +import type { HexagonPatternsType } from '../types' + +export function updateHexagonPatterns( + totalRows: number, + imagesPerRow: number +): HexagonPatternsType { + const patterns: HexagonPatternsType = [] + for (let i = 0; i < totalRows; i++) { + patterns[i] = generateRowPattern(i, imagesPerRow, totalRows) + } + return patterns +} diff --git a/modules/nuc_animations/hexagons/utils/update_images_per_row.ts b/modules/nuc_animations/hexagons/utils/update_images_per_row.ts new file mode 100644 index 0000000..a8d2944 --- /dev/null +++ b/modules/nuc_animations/hexagons/utils/update_images_per_row.ts @@ -0,0 +1,23 @@ +import { calculateDimensions, updateHexagonPatterns } from '.' +import type { HexagonConfigInterface, HexagonPatternsType } from '../types' + +export const updateImagesPerRow = ( + containerRef: HTMLElement | null, + setImagesPerRow: (value: number) => void, + setTotalRows: (value: number) => void, + setHexagonRows: (value: HexagonPatternsType) => void +): void => { + if (!containerRef) return + + const { + imagesPerRow: calculatedImages, + totalRows: calculatedRows, + }: HexagonConfigInterface = calculateDimensions( + containerRef.clientWidth, + containerRef.clientHeight + ) + + setImagesPerRow(calculatedImages) + setTotalRows(calculatedRows) + setHexagonRows(updateHexagonPatterns(calculatedRows, calculatedImages)) +} diff --git a/modules/nuc_animations/hexagons/variables/index.ts b/modules/nuc_animations/hexagons/variables/index.ts new file mode 100644 index 0000000..9ba170b --- /dev/null +++ b/modules/nuc_animations/hexagons/variables/index.ts @@ -0,0 +1 @@ +export * from './options' diff --git a/modules/nuc_animations/hexagons/variables/options.ts b/modules/nuc_animations/hexagons/variables/options.ts new file mode 100644 index 0000000..c1160d3 --- /dev/null +++ b/modules/nuc_animations/hexagons/variables/options.ts @@ -0,0 +1,5 @@ +export const HEXAGON_WIDTH = 40 +export const HEXAGON_HEIGHT = 40 +export const PATTERN_UPDATE_INTERVAL = 350 +export const HEXAGON_OVERLAP_FACTOR = 2 +export const HEXAGON_WIDTH_FACTOR = 2 diff --git a/modules/nuc_animations/index.ts b/modules/nuc_animations/index.ts new file mode 100644 index 0000000..f05cdc9 --- /dev/null +++ b/modules/nuc_animations/index.ts @@ -0,0 +1,13 @@ +/** + * Module's main file export + */ +export * from './nuc_animations' + +/** + * Folders exports + */ +export * from './hexagons' + +/** + * File exports + */ diff --git a/modules/nuc_animations/nuc_animations.ts b/modules/nuc_animations/nuc_animations.ts new file mode 100644 index 0000000..b51e2bf --- /dev/null +++ b/modules/nuc_animations/nuc_animations.ts @@ -0,0 +1,5 @@ +import { NucAnimationHexagons } from '.' + +export function registerNucAnimations(): void { + void NucAnimationHexagons +} diff --git a/modules/nuc_animations/rotate/_index.scss b/modules/nuc_animations/rotate/_index.scss new file mode 100644 index 0000000..0cdd76a --- /dev/null +++ b/modules/nuc_animations/rotate/_index.scss @@ -0,0 +1 @@ +@import 'keyframes'; diff --git a/modules/nuc_animations/rotate/_keyframes.scss b/modules/nuc_animations/rotate/_keyframes.scss new file mode 100644 index 0000000..98e39d9 --- /dev/null +++ b/modules/nuc_animations/rotate/_keyframes.scss @@ -0,0 +1,9 @@ +@keyframes rotate-right { + 0% { + transform: rotate(0); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/modules/nuc_animations/shine/_index.scss b/modules/nuc_animations/shine/_index.scss new file mode 100644 index 0000000..b2fd7bc --- /dev/null +++ b/modules/nuc_animations/shine/_index.scss @@ -0,0 +1,50 @@ +@import 'keyframes'; + +.shiny, +%shiny { + position: relative; + display: inline-block; + + & > div[aria-hidden='true'] { + position: relative; + display: inline-block; + + &:nth-child(1) { animation-delay: 0s; } + &:nth-child(2) { animation-delay: 0.2s; } + &:nth-child(3) { animation-delay: 0.4s; } + &:nth-child(4) { animation-delay: 0.6s; } + &:nth-child(5) { animation-delay: 0.8s; } + &:nth-child(6) { animation-delay: 1.0s; } + &:nth-child(7) { animation-delay: 1.2s; } + &:nth-child(8) { animation-delay: 1.4s; } + &:nth-child(9) { animation-delay: 1.6s; } + &:nth-child(10) { animation-delay: 1.8s; } + + animation: letter-shine 10s linear infinite; + } + + &:not(:has(> div[aria-hidden='true'])) { + animation: letter-shine 10s linear infinite; + } + + &.first-text { + & > div[aria-hidden='true'] { + animation-duration: 5.5s; + } + } + + &:not(.first-text) { + & > div[aria-hidden='true'] { + animation-duration: 5s; + } + } +} + +#back-office { + .shiny, + %shiny { + &:not(:has(> div[aria-hidden='true'])) { + animation: shiny-cube 10s linear infinite; + } + } +} diff --git a/modules/nuc_animations/shine/_keyframes.scss b/modules/nuc_animations/shine/_keyframes.scss new file mode 100644 index 0000000..20408d0 --- /dev/null +++ b/modules/nuc_animations/shine/_keyframes.scss @@ -0,0 +1,59 @@ +@keyframes shine { + to { + background-position: 200% center; + } +} + +@keyframes letter-shine { + 0%, 100% { + color: #1bbd79; + text-shadow: 0 0 10px rgb(27 189 121 / 50%); + } + + 20% { + color: #1bbd79; + text-shadow: 0 0 10px rgb(27 189 121 / 50%); + } + + 40% { + color: #178a59; + text-shadow: 0 0 8px rgb(23 138 89 / 40%); + } + + 60% { + color: #126543; + text-shadow: 0 0 6px rgb(18 101 67 / 30%); + } + + 80% { + color: #178a59; + text-shadow: 0 0 8px rgb(23 138 89 / 40%); + } +} + +@keyframes shiny-cube { + 0%, 100% { + color: $main-color-user; + text-shadow: 0 0 10px rgb(27 189 121 / 50%); + } + + 20% { + color: $main-focus-color-user; + text-shadow: 0 0 10px rgb(27 189 121 / 50%); + } + + 40% { + color: $main-color-user; + text-shadow: 0 0 8px rgb(23 138 89 / 40%); + } + + 60% { + color: $main-focus-color-user; + text-shadow: 0 0 6px rgb(18 101 67 / 30%); + } + + 80% { + color: $main-hover-color-user; + text-shadow: 0 0 8px rgb(23 138 89 / 40%); + } +}