9 Commits

Author SHA1 Message Date
73ea28eab6 finished table controls 2025-12-12 11:35:56 +10:00
ea0b091c8a table added 2025-12-12 10:57:38 +10:00
c53abdb678 added table controls 2025-12-12 10:10:30 +10:00
2b4a36c1ff details BEM 2025-12-11 22:26:18 +10:00
03e7b28167 details page in progress 2025-12-11 21:58:56 +10:00
a25b444c01 stylus mixins 2025-12-11 20:47:40 +10:00
d54afa7b2e BEM naming 2025-12-11 20:41:43 +10:00
01dfe8011d main page working 2025-12-11 19:59:17 +10:00
deeb9dbd5c added stylus template 2025-12-10 12:24:54 +10:00
13 changed files with 820 additions and 554 deletions

57
package-lock.json generated
View File

@@ -713,11 +713,10 @@
} }
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "4.0.13", "version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT",
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -735,6 +734,18 @@
"acorn": "^4.0.4" "acorn": "^4.0.4"
} }
}, },
"node_modules/acorn-globals/node_modules/acorn": {
"version": "4.0.13",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
"integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-import-phases": { "node_modules/acorn-import-phases": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
@@ -3261,6 +3272,18 @@
"object-assign": "^4.0.1" "object-assign": "^4.0.1"
} }
}, },
"node_modules/is-expression/node_modules/acorn": {
"version": "4.0.13",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
"integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/is-extglob": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5861,19 +5884,6 @@
} }
} }
}, },
"node_modules/terser/node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/terser/node_modules/commander": { "node_modules/terser/node_modules/commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -6375,19 +6385,6 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/webpack/node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/websocket-driver": { "node_modules/websocket-driver": {
"version": "0.7.4", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",

View File

@@ -1,81 +1,306 @@
block variables
- -
const pages = { var navbarItems = {
embedded: { Home: './index.html',
title: 'Embedded Details', Embedded: './embeded_details.html',
slug: 'embedded', OpenCV: './opencv_details.html',
menuTitle: 'Embeded Details', Photography: './photography-details.html',
images: [ Table: './table.html',
{ src: './images/esp32.png', alt: 'ESP32', height: 150 }, Institute: './images/institute.png'
{ src: './images/arduino.png', alt: 'Arduino', height: 150 }, };
{ src: './images/stm32.png', alt: 'STM32', height: 150 }
],
paragraphs: [
"My programming path started with embeded systems, i love all the low level things that Mcu could do with just a little bit of code, sometimes build or flashing progress could take some time to get a hand of , but after that everething usualy goes smooth",
"The first MCU i tried was a ATmega328P, after some time i was surprised with the debug capabilities on the Stm32 and now i'm working with esp32-s3 , that's a good chip, has internal JTAG and all the shiny wireless interfaces but feels faulty for some reason <i>regular segfaults with CDC</i>"
],
table: {
title: 'Microcontroller Comparison Table',
headers: ['Board/MCU', 'UART Count', 'Dynamic UART Assignment', 'ADC Channels', 'Debug Support', 'Flash Size', 'Wireless Connectivity'],
rows: [
['ESP32', '3', 'Yes (via IO MUX)', '18', 'JTAG, Serial', '4MB (typical)', 'Wi-Fi, Bluetooth'],
['ESP32-S3', '3', 'Yes (via IO MUX)', '20', 'JTAG, Serial', '8MB (typical)', 'Wi-Fi, Bluetooth LE'],
['ESP-01', '1', 'No', '1', 'Serial only', '512KB/1MB', 'Wi-Fi'],
['Arduino Uno (ATmega328P)', '1', 'No', '6', 'Serial, DebugWire', '32KB', 'None'],
['Blue Pill (STM32F103C8T6)', '3', 'Yes (remappable)', '10', 'SWD, Serial', '64KB/128KB', 'None']
]
},
footer: "no rpi pico here , the build system has won over my temper"
},
opencv: { var smallCards = [
title: 'OpenCV Details', {
slug: 'opencv', header: 'Заголовок',
menuTitle: 'OpenCV Details', text: '3D printers are versatile tools used for creating prototypes, custom parts, and artistic designs. They work by layering materials.',
images: [ image: require('../images/16x10/3d-printer.jpeg'),
{ src: './images/opencv.png', alt: 'OpenCV', height: 150 } imageAlt: '3D Printer',
], link: '#',
paragraphs: [ },
"as mentioned before i love when programs are able to <i>see</i> things", {
"my experience with opencv started with simple hight level functions like detectCircle or findContours and etc...", header: 'BLHeli ESCs',
"Right now i'm crawling deeper into the library , and the idea of standartisation of parameters between different cameras is appealig to me", text: 'BLHeli ESCs are electronic speed controllers designed for drones, offering smooth and precise motor control.',
"so i'm trying to understand how all that works from the math side", image: require('../images/16x10/blheli-esc.jpeg'),
"Additionally, I'm exploring Re-Identification (ReId) techniques, they are used for recognizing and tracking objects across different camera views or consecutive frames." imageAlt: 'BLHeli ESC',
], link: '#',
content: { },
type: 'text', {
text: "One of many projects I've worked on is <a href=\"https://github.com/OkunElya/ArucoNGP-MapCreator\" target=\"_blank\">ArucoNGP-MapCreator</a>.<br>The idea was to create a relative map of Aruco markers just from photos of pairs (or more) of them.<br>It can also estimate the camera's position in the world relative to a specific marker, using only images containing any marker.<br>It was also my first deep dive into linear algebra." header: 'Raspberry Pi Nano',
} text: 'Raspberry Pi Nano is a compact computer ideal for learning, prototyping, and IoT projects. It is highly energy-efficient.',
}, image: require('../images/16x10/rpi-nano.jpeg'),
imageAlt: 'Raspberry Pi Nano',
link: '#',
},
{
header: 'Smart Thermostats',
text: 'Smart thermostats help regulate home temperatures efficiently, saving energy and enhancing comfort with automation.',
image: require('../images/16x10/thermostat.jpeg'),
imageAlt: 'Smart Thermostat',
link: '#',
}
];
photography: { var galleryImages= [
title: 'Photography Details', { src: require('../images/sqarucos.png'), alt: 'ESP32'},
slug: 'photography', { src: require('../images/sqstm32.png'), alt: 'Arduino'},
menuTitle: 'Photography Details', { src: require('../images/sqesp32.png'), alt: 'STM32'}
images: [], ];
paragraphs: [
"Usually i capture landcape scenes with SLR camera, the main workhorse is Nikon D3100 with kit and 70-210mm"
],
gallery: [
[
{ src: 'images/photos/image0.png', alt: 'Photo 0', width: 200 },
{ src: 'images/photos/image1.png', alt: 'Photo 1', width: 200 },
{ src: 'images/photos/image2.png', alt: 'Photo 2', width: 200 }
],
[
{ src: 'images/photos/image3.png', alt: 'Photo 3', width: 200 },
{ src: 'images/photos/image4.png', alt: 'Photo 4', width: 200 },
{ src: 'images/photos/image5.png', alt: 'Photo 5', width: 200 }
]
]
}
};
- var locationFilters = [
const menu = [ { id: 'loc_kitchen', value: 'Kitchen', label: 'Kitchen' },
{ href: './index.html', title: 'Home' }, { id: 'loc_living', value: 'Living Room', label: 'Living Room' },
{ href: './embeded_details.html', title: 'Embeded Details' }, { id: 'loc_balcony', value: 'Balcony', label: 'Balcony' },
{ href: './opencv_details.html', title: 'OpenCV Details' }, { id: 'loc_bedroom', value: 'Bedroom', label: 'Bedroom' }
{ href: './photography_details.html', title: 'Photography Details' }, ];
{ href: './table.html', title: 'Table with filters (not working yet)' },
{ href: './images/institute.png', title: 'Institute' } var sensorTypeFilters = [
]; { id: 'type_xiaomi', value: 'Xiaomi', label: 'Xiaomi' },
{ id: 'type_bmp220', value: 'Bmp220', label: 'Bmp220' },
{ id: 'type_scd30', value: 'Scd30(Internal)', label: 'Scd30(Internal)' },
{ id: 'type_bmp280', value: 'Bmp280', label: 'Bmp280' }
];
var sortOptions = [
{ value: '', label: '-- None --' },
{ value: 'SensorID', label: 'SensorID' },
{ value: 'Timestamp', label: 'Time' },
{ value: 'BatteryLevel', label: 'BatteryLevel' },
{ value: 'Temperature', label: 'Temperature' },
{ value: 'Humidity', label: 'Humidity' }
];
var axisOptions = [
{ id: 'x_time', value: 'Time', label: 'Time', checked: true },
{ id: 'x_battery', value: 'BatteryLevel', label: 'BatteryLevel', checked: false },
{ id: 'x_temperature', value: 'Temperature', label: 'Temperature', checked: false },
{ id: 'x_humidity', value: 'Humidity', label: 'Humidity', checked: false }
];
var valueOptions = [
{ id: 'val_temperature', value: 'AverageTemperature', label: 'Average Temperature', checked: true },
{ id: 'val_humidity', value: 'Humidity', label: 'Average Humidity', checked: false },
{ id: 'val_battery', value: 'BatteryLevel', label: 'Average BatteryLevel', checked: false }
]
var sensorData = [
{
sensorId: 'TEMP-001',
location: 'Balcony',
timestamp: '2025-10-03T03:41:50Z',
temperature: 19.4,
tempDifference: -0.2,
sensorType: 'Bmp220',
batteryLevel: 95,
humidity: 38.1,
lastCalibrationDate: '2025-07-26'
},
{
sensorId: 'TEMP-003',
location: 'Bedroom',
timestamp: '2025-10-03T03:42:46Z',
temperature: 18.2,
tempDifference: -0.1,
sensorType: 'Xiaomi',
batteryLevel: 75,
humidity: 45.5,
lastCalibrationDate: '2025-07-21'
},
{
sensorId: 'TEMP-004',
location: 'Balcony',
timestamp: '2025-10-03T03:43:48Z',
temperature: 24.1,
tempDifference: 0.1,
sensorType: 'Xiaomi',
batteryLevel: 72,
humidity: 50.5,
lastCalibrationDate: '2025-08-30'
},
{
sensorId: 'TEMP-001',
location: 'Balcony',
timestamp: '2025-10-03T03:44:34Z',
temperature: 19.1,
tempDifference: -0.3,
sensorType: 'Bmp220',
batteryLevel: 95,
humidity: 56.5,
lastCalibrationDate: '2025-07-26'
},
{
sensorId: 'TEMP-006',
location: 'Kitchen',
timestamp: '2025-10-03T03:45:46Z',
temperature: 22.8,
tempDifference: 0.0,
sensorType: 'Scd30(Internal)',
batteryLevel: 80,
humidity: 41.4,
lastCalibrationDate: '2025-09-10'
},
{
sensorId: 'TEMP-010',
location: 'Balcony',
timestamp: '2025-10-03T03:46:18Z',
temperature: 21.7,
tempDifference: 0.5,
sensorType: 'Scd30(Internal)',
batteryLevel: 79,
humidity: 59.8,
lastCalibrationDate: '2025-08-07'
},
{
sensorId: 'TEMP-006',
location: 'Balcony',
timestamp: '2025-10-03T03:47:05Z',
temperature: 22.7,
tempDifference: -0.1,
sensorType: 'Scd30(Internal)',
batteryLevel: 80,
humidity: 36.1,
lastCalibrationDate: '2025-09-10'
},
{
sensorId: 'TEMP-006',
location: 'Bedroom',
timestamp: '2025-10-03T03:48:13Z',
temperature: 22.9,
tempDifference: 0.2,
sensorType: 'Scd30(Internal)',
batteryLevel: 80,
humidity: 56.1,
lastCalibrationDate: '2025-09-10'
},
{
sensorId: 'TEMP-005',
location: 'Living Room',
timestamp: '2025-10-03T03:49:03Z',
temperature: 24.4,
tempDifference: 0.4,
sensorType: 'Bmp180',
batteryLevel: 91,
humidity: 30.1,
lastCalibrationDate: '2025-08-07'
},
{
sensorId: 'TEMP-001',
location: 'Kitchen',
timestamp: '2025-10-03T03:50:24Z',
temperature: 19.1,
tempDifference: 0.0,
sensorType: 'Bmp220',
batteryLevel: 95,
humidity: 64.8,
lastCalibrationDate: '2025-07-26'
},
{
sensorId: 'TEMP-008',
location: 'Living Room',
timestamp: '2025-10-03T03:51:12Z',
temperature: 21.9,
tempDifference: -0.1,
sensorType: 'Scd30(Internal)',
batteryLevel: 92,
humidity: 36.0,
lastCalibrationDate: '2025-08-02'
},
{
sensorId: 'TEMP-009',
location: 'Balcony',
timestamp: '2025-10-03T03:51:46Z',
temperature: 22.3,
tempDifference: 0.0,
sensorType: 'Xiaomi',
batteryLevel: 76,
humidity: 74.0,
lastCalibrationDate: '2025-09-17'
},
{
sensorId: 'TEMP-003',
location: 'Kitchen',
timestamp: '2025-10-03T03:52:23Z',
temperature: 18.4,
tempDifference: 0.2,
sensorType: 'Xiaomi',
batteryLevel: 75,
humidity: 45.2,
lastCalibrationDate: '2025-07-21'
},
{
sensorId: 'TEMP-010',
location: 'Living Room',
timestamp: '2025-10-03T03:53:44Z',
temperature: 21.8,
tempDifference: 0.1,
sensorType: 'Scd30(Internal)',
batteryLevel: 79,
humidity: 36.3,
lastCalibrationDate: '2025-08-07'
},
{
sensorId: 'TEMP-001',
location: 'Kitchen',
timestamp: '2025-10-03T03:54:46Z',
temperature: 18.7,
tempDifference: -0.4,
sensorType: 'Bmp220',
batteryLevel: 95,
humidity: 44.3,
lastCalibrationDate: '2025-07-26'
},
{
sensorId: 'TEMP-006',
location: 'Bedroom',
timestamp: '2025-10-03T03:55:24Z',
temperature: 23.3,
tempDifference: 0.4,
sensorType: 'Scd30(Internal)',
batteryLevel: 80,
humidity: 55.9,
lastCalibrationDate: '2025-09-10'
},
{
sensorId: 'TEMP-002',
location: 'Kitchen',
timestamp: '2025-10-03T03:55:57Z',
temperature: 17.7,
tempDifference: -0.5,
sensorType: 'Scd30(Internal)',
batteryLevel: 93,
humidity: 70.2,
lastCalibrationDate: '2025-08-30'
},
{
sensorId: 'TEMP-002',
location: 'Balcony',
timestamp: '2025-10-03T03:57:05Z',
temperature: 17.4,
tempDifference: -0.3,
sensorType: 'Scd30(Internal)',
batteryLevel: 93,
humidity: 66.7,
lastCalibrationDate: '2025-08-30'
},
{
sensorId: 'TEMP-009',
location: 'Living Room',
timestamp: '2025-10-03T03:58:28Z',
temperature: 22.6,
tempDifference: 0.3,
sensorType: 'Xiaomi',
batteryLevel: 76,
humidity: 56.4,
lastCalibrationDate: '2025-09-17'
},
{
sensorId: 'TEMP-004',
location: 'Bedroom',
timestamp: '2025-10-03T03:59:51Z',
temperature: 24.3,
tempDifference: 0.2,
sensorType: 'Xiaomi',
batteryLevel: 72,
humidity: 47.3,
lastCalibrationDate: '2025-08-30'
}
];

View File

@@ -0,0 +1,24 @@
include mixins.pug
html
head
meta(charset="UTF-8")
block title
title Details Page
body
block navbar
+navbarMixin("")
.details
header.details__header
block header
h1 Default Header
.details__content
.details__text
block text
p Default text content
.details__gallery
block gallery
p No images available

158
src/components/mixins.pug Normal file
View File

@@ -0,0 +1,158 @@
include data.pug
mixin navbarMixin(selectedItem)
.navbar
each navbarUrl,navbarName in navbarItems
if navbarName == selectedItem
a.navbar__link-wrapper(href=navbarUrl)
.navbar__item.navbar__item_selected #{navbarName}
else
a.navbar__link-wrapper(href=navbarUrl)
.navbar__item #{navbarName}
mixin infoCardsMinxin()
each cardData in smallCards
.small-card
.small-card__content
h3.small-card__header #{cardData.header}
p.small-card__text #{cardData.text}
a.small-card__link(href=cardData.link) Подробнее»
.small-card__image
img(src=cardData.image alt=cardData.imageAlt)
mixin galleryMixin()
each img in galleryImages
img.gallery__image(src=img.src alt=img.alt)
mixin filtersMixin()
details.filters
summary.filters__summary Filters
form.filters__form
fieldset.filters__fieldset
.filter-group
i.filter-group__label
b Location
br
.filter-group__items
each filter in locationFilters
input.filter-group__checkbox(type="checkbox" id=filter.id name="location" value=filter.value)
span #{filter.label}
br
.filter-group
i.filter-group__label
b Sensor Type
br
.filter-group__items
each filter in sensorTypeFilters
input.filter-group__checkbox(type="checkbox" id=filter.id name="sensor_type" value=filter.value)
span #{filter.label}
br
.filter-group
i.filter-group__label
b Numeric Values
br
.filter-group__range
span Temperature from:
input.filter-group__input(type="number" name="temp_min" placeholder="20")
span to:
input.filter-group__input(type="number" name="temp_max" placeholder="30")
br
span Humidity from:
input.filter-group__input(type="number" name="humidity_min" placeholder="40")
span to:
input.filter-group__input(type="number" name="humidity_max" placeholder="60")
br
.filter-group
i.filter-group__label
b Device Specific Filters
br
.filter-group__items
span Sensor Name:
input.filter-group__input(type="text" name="sensor_name")
br
span Days Since Calibration (max):
input.filter-group__input(type="number" name="calibration_days" placeholder="30")
br
.filter-group
i.filter-group__label
b Measurement Period
br
.filter-group__dates
span From:
input.filter-group__input(type="date" name="date_from")
br
span To:
input.filter-group__input(type="date" name="date_to")
br
.filter-group__buttons
input.filter-group__button.filter-group__button--submit(type="submit" value="Apply Filters")
input.filter-group__button.filter-group__button--reset(type="reset" value="Reset Filters")
mixin sortLevel(level)
.sort-level
i.sort-level__label
b Sort Level #{level}
br
label.sort-level__field-label(for=`sort${level}`) Field:
select.sort-level__select(id=`sort${level}` name=`sort${level}`)
each option in sortOptions
option(value=option.value) #{option.label}
label.sort-level__reverse-label(for=`sort${level}_reverse`)
input.sort-level__checkbox(type="checkbox" id=`sort${level}_reverse` name=`sort${level}_reverse`)
span Reverse
br
if level === '3'
input.sort-level__submit(type="submit" value="Sort")
else
br
mixin sortingMixin()
- const sortLevels = ['1', '2', '3'];
details.sorting
summary.sorting__summary Sortings
form.sorting__form
fieldset.sorting__fieldset
each level in sortLevels
+sortLevel(level)
mixin graphXOption(option)
if option.checked
input.axis-group__radio(type="radio" id=option.id name="x_axis" value=option.value checked)
else
input.axis-group__radio(type="radio" id=option.id name="x_axis" value=option.value)
label.axis-group__option-label(for=option.id) #{option.label}
br
mixin graphYOption(option)
if option.checked
input.values-group__checkbox(type="checkbox" id=option.id name="values" value=option.value checked)
else
input.values-group__checkbox(type="checkbox" id=option.id name="values" value=option.value)
label.values-group__option-label(for=option.id) #{option.label}
br
mixin graphMixin()
details.graph
summary.graph__summary Graph
form.graph__form
fieldset.graph__fieldset
.axis-group
i.axis-group__label
b X axis
br
.axis-group__options
each option in axisOptions
+graphXOption(option)
.values-group
i.values-group__label
b Values
br
.values-group__options
each option in valueOptions
+graphYOption(option)
button.values-group__button(type="submit" id="build_graph" name="build_graph") Build

View File

@@ -1,69 +0,0 @@
include data.pug
mixin detailsPage(pageData)
doctype html
html(lang="en")
head
meta(charset="UTF-8")
title= pageData.title
body(bgcolor="#F0F8FF")
//- Menu
details
summary Menu
ul
each item in menu
li
if item.title === pageData.menuTitle
a(href=item.href)
h4= item.title
else
a(href=item.href)= item.title
//- Page Title
h2(align="center")= pageData.title
hr(width="800" align="center")
//- Header Images
if pageData.images && pageData.images.length > 0
p(align="center")
each img in pageData.images
if img.height
img(src=img.src alt=img.alt height=img.height)
else if img.width
img(src=img.src alt=img.alt width=img.width)
else
img(src=img.src alt=img.alt)
//- Paragraphs
if pageData.paragraphs
each para in pageData.paragraphs
p(align="justify")!= para
//- Table (for embedded page)
if pageData.table
h3(align="center")= pageData.table.title
table(border="1" align="center" cellpadding="6" cellspacing="0")
tr
each header in pageData.table.headers
th= header
each row in pageData.table.rows
tr
each cell in row
td= cell
//- Content (for opencv page)
if pageData.content
hr(width="500" align="center")
p!= pageData.content.text
//- Gallery (for photography page)
if pageData.gallery
each row in pageData.gallery
p(align="center")
each img in row
img(src=img.src alt=img.alt width=img.width)
//- Footer
if pageData.footer
p(align="right")= pageData.footer

View File

@@ -1 +1,3 @@
import './styles/main.styl' import './styles/index.styl'
import './styles/details.styl'
import './styles/table.styl'

View File

@@ -1,140 +1,51 @@
include ../components/mixins.pug
- -
const menuItems = [ const infoBlockA = {
{ href: './index.html', title: 'Home', isActive: true }, header: "Embedded Systems",
{ href: './embeded_details.html', title: 'Embedded' }, text: "Had a serval projects with different MCUs and wrote firmware for them. My main stack consists of Platformio+EspIdf or Arduino, also tried STM32 asdadas",
{ href: './opencv_details.html', title: 'OpenCV' }, description: "I love embeded development beceuse of autonomity of produced devices, the redices are not dependant on any other hardware and can work autunomously",
{ href: './photography_details.html', title: 'Photography' }, img: require('../images/AQ_monitor.png'),
{ href: './table.html', title: 'Table' }, imgAlt: "ESP32"
{ href: './images/institute.png', title: 'Institute' }
];
const galleryImages = [
{ src: './images/sqarucos.png', alt: 'Arduino' },
{ src: './images/sqstm32.png', alt: 'STM32' },
{ src: './images/sqesp32.png', alt: 'ESP32' }
];
const contentBlocks = [
{
title: 'Embedded Systems',
image: './images/AQ_monitor.png',
imageAlt: 'ESP32',
columns: [
{ text: 'Had several projects with different MCUs and wrote firmware for them. My main stack consists of Platformio+EspIdf or Arduino, also tried STM32' },
{ text: 'I love embedded development because of autonomy of produced devices, the devices are not dependent on any other hardware and can work autonomously', hasLink: true }
]
},
{
title: 'Embedded Systems',
image: './images/remote.jpeg',
imageAlt: 'Remote',
imageCenter: true,
columns: [
{ text: 'Had several projects with different MCUs and wrote firmware for them. My main stack consists of Platformio+EspIdf or Arduino, also tried STM32' },
{ text: 'I love embedded development because of autonomy of produced devices, the devices are not dependent on any other hardware and can work autonomously or off the grid', hasLink: true }
]
} }
]; const infoBlockB = {
header: "Embedded Systems",
const sidebarBlocks = [ text: "Had a serval projects with different MCUs and wrote firmware for them. My main stack consists of Platformio+EspIdf or Arduino, also tried STM32",
{ description: "I love embeded development device because of autonomity of produced devices, the devices are not dependant on any other hardware and can work autunomously or off the grid",
title: '3D Printer', img: require('../images/remote.jpeg'),
text: '3D printers are versatile tools used for creating prototypes, custom parts, and artistic designs. They work by layering materials.', imgAlt: "ESP32"
image: 'images/16x10/3d-printer.jpeg',
alt: '3D Printer'
},
{
title: 'BLHeli ESCs',
text: 'BLHeli ESCs are electronic speed controllers designed for drones, offering smooth and precise motor control.',
image: 'images/16x10/blheli-esc.jpeg',
alt: 'BLHeli ESC'
},
{
title: 'Raspberry Pi Nano',
text: 'Raspberry Pi Nano is a compact computer ideal for learning, prototyping, and IoT projects. It is highly energy-efficient.',
image: 'images/16x10/rpi-nano.jpeg',
alt: 'Raspberry Pi Nano'
},
{
title: 'Smart Thermostats',
text: 'Smart thermostats help regulate home temperatures efficiently, saving energy and enhancing comfort with automation.',
image: 'images/16x10/thermostat.jpeg',
alt: 'Smart Thermostat'
} }
];
mixin nav-menu(items)
nav.nav
ul.nav__list
each item in items
li.nav__item
a.nav__link(href=item.href class=item.isActive ? 'nav__link--active' : '')= item.title
mixin gallery(images)
.gallery
each img in images
.gallery__item
img.gallery__image(src=img.src alt=img.alt)
mixin content-block(block, index)
.content-block
.content-block__header
h5.content-block__title= block.title
.content-block__body(class=`content-block__body--layout-${index % 2 === 0 ? 'a' : 'b'}`)
if index % 2 === 0
each col in block.columns
.content-block__column
p.content-block__text= col.text
if col.hasLink
a.content-block__link(href="#") More info»
.content-block__column.content-block__column--image
img.content-block__image(src=block.image alt=block.imageAlt)
else
.content-block__column
p.content-block__text= block.columns[0].text
.content-block__column.content-block__column--image-center
img.content-block__image(src=block.image alt=block.imageAlt)
.content-block__column
p.content-block__text= block.columns[1].text
if block.columns[1].hasLink
a.content-block__link(href="#") More info»
mixin sidebar-card(card)
.sidebar-card
.sidebar-card__content
h6.sidebar-card__title= card.title
p.sidebar-card__text= card.text
a.sidebar-card__link(href="#") More Info»
.sidebar-card__image-wrapper
img.sidebar-card__image(src=card.image alt=card.alt)
doctype html
html(lang="en") html(lang="en")
head head
meta(charset="UTF-8") meta(charset="UTF-8")
meta(name="viewport" content="width=device-width, initial-scale=1") title Portfolio
link(rel="stylesheet" href="styles/index.css")
title Portfolio
body.page body
//- Navigation +navbarMixin("Home")
+nav-menu(menuItems)
//- Image Gallery .gallery
+gallery(galleryImages) +galleryMixin()
//- Main Content .main-container
.main .main-container__content
.main__content article.info-block
each block, index in contentBlocks h2.info-block__header #{infoBlockA.header}
+content-block(block, index) .info-block__container.info-block__container_layout-a
p.info-block__text #{infoBlockA.text}
.info-block__details
p.info-block__description #{infoBlockA.description}
a.info-block__link(href="#") More info
img.info-block__image(src=infoBlockA.img alt=infoBlockA.imgAlt)
//- Sidebar article.info-block
.main__sidebar h2.info-block__header #{infoBlockB.header}
each card in sidebarBlocks .info-block__container.info-block__container_layout-b
+sidebar-card(card) p.info-block__text #{infoBlockB.text}
img.info-block__image(src=infoBlockB.img alt=infoBlockB.imgAlt)
.info-block__details
p.info-block__description #{infoBlockB.description}
a.info-block__link(href="./photography-details.html") More info
//- Footer .sidebar
footer.footer +infoCardsMinxin()
span.footer__text Kulesh A.
span.footer__text Б9123-09.03.04

View File

@@ -0,0 +1,22 @@
extends ../components/details-template.pug
block title
title Photography Portfolio - Details
block navbar
+navbarMixin("Photography")
block header
h1.details__title Photography
p.details__description I prefer landscape photography.
block text
p.details__text-content D3100 -> SLT A58.
block gallery
.details__gallery-item
img.details__gallery-image(src=require('../images/photos/image0.png') alt="Photography 1")
.details__gallery-item
img.details__gallery-image(src=require('../images/photos/image1.png') alt="Photography 2")
.details__gallery-item
img.details__gallery-image(src=require('../images/photos/image2.png') alt="Photography 3")

25
src/pages/table.pug Normal file
View File

@@ -0,0 +1,25 @@
include ../components/mixins.pug
include ../components/data.pug
head
title table
body
+navbarMixin("Table")
.table-controls
+filtersMixin()
+sortingMixin()
+graphMixin()
table.table
tbody.table-content
each dataItem,index in sensorData
if index == 0
tr.table-content__table-header
each value,header in dataItem
th #{header}
tr.table-content__table-row
each value,header in dataItem
td #{value}

58
src/styles/details.styl Normal file
View File

@@ -0,0 +1,58 @@
.details
margin 0 auto
padding 20px
.details__header
margin-bottom 20px
text-align center
.details__title
margin-bottom 5px
.details__description
margin auto
.details__content
display flex
gap 40px
align-items flex-start
.details__text
flex 1
text-align justify
.details__text-content
margin auto 30px
.details__gallery
display flex
flex-direction column
gap 20px
margin auto
.details__gallery-item
overflow hidden
border-radius 8px
box-shadow 0 4px 12px rgba(0, 0, 0, 0.1)
transition transform 0.3s ease, box-shadow 0.3s ease
&:hover
transform translateY(-5px)
box-shadow 0 8px 20px rgba(0, 0, 0, 0.15)
.details__gallery-image
width 100%
height 250px
object-fit cover
display block
@media screen and (max-width: 700px)
.details__content
flex-direction column
.details__gallery
order -1 // Move gallery above text
.details__gallery-image
height 300px

View File

@@ -1,259 +1,166 @@
// Variables item_h=3em;
$color-bg = #F0F8FF
$color-text = black
$color-primary = green
$color-border = silver
$color-footer-bg = #f8f9fa
$border-thin = 1px solid black double-border()
$border-double = double 4px silver border-top double thick silver
$border-double-thick = double thick silver border-bottom double thick silver
$spacing-sm = 10px
$spacing-md = 20px
$spacing-lg = 30px
$spacing-xl = 50px
$breakpoint-mobile = 800px
$breakpoint-tablet = 1000px
// Mixins
flex-center() flex-center()
display flex display flex
align-items center align-items center
justify-content center justify-content center
text-justify() text-center-bold()
text-align justify
border-block()
border $border-thin
padding 2vw
margin 1vw 0
// Base
*
box-sizing border-box
margin 0
padding 0
.page
font-family Arial, sans-serif
background-color $color-bg
color $color-text
// Navigation (БЭМ)
.nav
border-top $border-double-thick
border-bottom $border-double-thick
&__list
display grid
grid-template-columns repeat(7, min-content)
grid-template-rows 1fr
justify-items start
list-style none
font-size 0
@media screen and (max-width: $breakpoint-mobile)
grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr 1fr
justify-items center
&__item
display inline-block
&__link
display block
width max-content
height 3em
line-height 3em
text-align center text-align center
padding 0 $spacing-sm font-weight bold
margin 0 $spacing-sm display block
color $color-text
text-decoration none
font-size medium
overflow hidden
text-overflow ellipsis
&--active grid-responsive(columns)
color $color-primary display grid
font-weight bold grid-template-columns columns
border-left $border-double grid-template-rows 1fr
border-right $border-double
@media screen and (max-width: $breakpoint-mobile) .navbar
border-left none double-border()
border-right none font-size 0
border-bottom $border-double-thick grid-responsive(repeat(7, min-content))
justify-items start
&__link-wrapper
color black
text-decoration none
&__item
display inline-block
width max-content
height item_h
line-height item_h
text-align center
vertical-align middle
padding 0 10px
margin @padding
overflow hidden
text-overflow ellipsis
font-size medium
&_selected
color green
font-weight bold
border-left double thin silver
border-right double thin silver
// Gallery (БЭМ)
.gallery .gallery
display flex display flex
flex-direction row flex-direction row
width 90% width 90%
margin auto
gap 0
@media screen and (max-width: $breakpoint-mobile)
flex-direction column
width 100%
&__item
flex 1
margin auto margin auto
&__image &__image
width 100% margin auto
height auto width 100%
border $border-thin border thin solid black
&:nth-child(odd) &:nth-child(2n+1)
margin-top $spacing-sm margin-top 10px
@media screen and (max-width: $breakpoint-mobile) .main-container
margin-top 0 grid-responsive(3fr 1fr)
// Main Layout (БЭМ)
.main
display grid
grid-template-columns 3fr 1fr
grid-template-rows 1fr
gap 0
@media screen and (max-width: $breakpoint-mobile) .info-block
display flex border solid thin black
flex-direction column padding 2vw
margin 1vw 0
&__content &__header
padding-right 0 text-center-bold()
&__sidebar &__container
border-left $border-thin &_layout-a
margin $spacing-lg 0 0 $spacing-xl grid-responsive(3fr 3fr 2fr)
padding-left $spacing-md
@media screen and (max-width: $breakpoint-mobile) &_layout-b
border-left none grid-responsive(4fr 7fr 4fr)
margin $spacing-lg 0 0 0
padding-left 0
// Content Block (БЭМ) & > *
.content-block margin 2vw
border-block()
&__header &__text, &__description
text-align center text-align justify
margin-bottom 1vw
&__title &__image
font-weight bold margin auto
font-size 1.2em width 100%
&__body &__link
&--layout-a color inherit
display grid
grid-template-columns 3fr 3fr 2fr
grid-template-rows 1fr
@media screen and (max-width: $breakpoint-mobile)
.sidebar
border-left thin solid black
margin 30px 0 0 50px
.small-card
margin 20px 10px 0
grid-responsive(1fr 1fr)
&__content
text-align justify
&__header
text-center-bold()
text-align right
&__link
display block
text-align right
color inherit
&__image
& img
width 100%
margin-left:10px
@media screen and (max-width: 1000px)
.small-card
display flex
flex-direction column
.sidebar
margin 0
width:100%
@media screen and (max-width: 800px)
.navbar
grid-responsive(1fr 1fr)
grid-template-rows 1fr 1fr 1fr
justify-items center
&__item
&_selected
border-bottom double thick silver
border-left none
border-right none
.gallery
display inline-flex
flex-direction column
width 100%
&__image
width 100%
height 100%
&:nth-child(2n+1)
margin-top 0px
.main-container
display flex display flex
flex-direction column flex-direction column
&--layout-b .info-block
display grid &__container
grid-template-columns 4fr 7fr 4fr &_layout-a, &_layout-b
grid-template-rows 1fr display flex
flex-direction column
@media screen and (max-width: $breakpoint-mobile)
display flex
flex-direction column
&__column
margin 2vw
&--image
flex-center()
&--image-center
flex-center()
grid-column 2
&__text
text-justify()
&__image
width 100%
height auto
&__link
display block
text-align right
margin-top $spacing-sm
color $color-text
text-decoration none
font-size 0.9em
&:hover
text-decoration underline
// Sidebar Card (БЭМ)
.sidebar-card
display grid
grid-template-columns 1fr 1fr
grid-template-rows auto
margin $spacing-md $spacing-sm 0
gap $spacing-sm
@media screen and (max-width: $breakpoint-tablet)
display flex
flex-direction column
&__content
display flex
flex-direction column
justify-content space-between
&__title
font-weight bold
text-align right
margin-bottom $spacing-sm
&__text
text-justify()
font-size 0.9em
margin-bottom $spacing-sm
&__link
display block
text-align right
color $color-text
text-decoration none
font-size 0.85em
&:hover
text-decoration underline
&__image-wrapper
overflow hidden
&__image
width 100%
height auto
display block
transition transform 0.3s ease
&:hover
transform scale(1.05)
// Footer (БЭМ)
.footer
background-color $color-footer-bg
padding 1em 2em
margin-top $spacing-lg
display flex
gap 2em
&__text
font-size 1.1em

View File

6
src/styles/table.styl Normal file
View File

@@ -0,0 +1,6 @@
.table, .table-content *, .table-content
border: 1px solid black;
border-collapse: collapse;
.table-content__table-row:nth-child(2n)
background: #F0FFF0;