Compare commits
7 commits
d39b85fbc7
...
2318a645ce
Author | SHA1 | Date | |
---|---|---|---|
2318a645ce | |||
4869352450 | |||
4bd4d08f06 | |||
0efc5a3362 | |||
e5c924f73b | |||
29102b4ad6 | |||
6d9e05c3e8 |
14 changed files with 1226 additions and 5451 deletions
6455
package-lock.json
generated
6455
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -10,8 +10,8 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^2.9.0",
|
||||
"astro-compress": "^1.1.50",
|
||||
"astro": "^2.10.5",
|
||||
"astro-compress": "^2.0.5",
|
||||
"intl": "^1.2.5",
|
||||
"less": "^4.1.3",
|
||||
"reading-time": "^1.5.0",
|
||||
|
|
BIN
public/assets/20220629-mvsp/devtools.jpg
Normal file
BIN
public/assets/20220629-mvsp/devtools.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
Before Width: | Height: | Size: 229 KiB |
|
@ -19,6 +19,7 @@ const {
|
|||
<div class="card card-elevated" id={post.slug}>
|
||||
<Article
|
||||
PostContent={PostContent}
|
||||
slug={post.slug}
|
||||
title={title}
|
||||
description={description}
|
||||
readingTime={readingTime}
|
||||
|
|
|
@ -35,6 +35,8 @@ const {
|
|||
@icon-size: 1.5rem;
|
||||
|
||||
li {
|
||||
height: fit-content;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
52
src/components/PageCtrlBtn.astro
Normal file
52
src/components/PageCtrlBtn.astro
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
import Icon from './Icon.astro';
|
||||
|
||||
export interface Props {
|
||||
btnKind: 'prev' | 'pagenum' | 'next';
|
||||
url?: string | undefined;
|
||||
num?: number;
|
||||
}
|
||||
|
||||
const { btnKind, url, num = 1 } = Astro.props;
|
||||
---
|
||||
|
||||
<a href={url ?? 'javascript:void(0)'} class={btnKind}>
|
||||
{
|
||||
btnKind === 'pagenum' ? <span class="pagenum">{num}</span> :
|
||||
btnKind === 'prev' ? <Icon code="" /> :
|
||||
btnKind === 'next' ? <Icon code="" /> :
|
||||
""
|
||||
}
|
||||
</a>
|
||||
|
||||
<style lang="less">
|
||||
a {
|
||||
@size: 1.1rem;
|
||||
@color: var(--fg);
|
||||
|
||||
width: @size;
|
||||
height: @size;
|
||||
box-sizing: content-box;
|
||||
|
||||
font-size: @size;
|
||||
padding: 0.625rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
color: @color;
|
||||
|
||||
&:hover {
|
||||
color: @color;
|
||||
|
||||
background: var(--accent-bg);
|
||||
border-radius: var(--bdrs);
|
||||
}
|
||||
}
|
||||
|
||||
.pagenum {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
82
src/components/ScrollToTop.astro
Normal file
82
src/components/ScrollToTop.astro
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
import Icon from "./Icon.astro";
|
||||
---
|
||||
|
||||
<div id="scroll-to-top" data-show="0">
|
||||
<a href="#">
|
||||
<Icon code="" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<style lang="less">
|
||||
@size: 2.25rem;
|
||||
@font: 1.50rem;
|
||||
|
||||
div {
|
||||
position: absolute;
|
||||
|
||||
&[data-show="0"] a {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease, height 0.2s step-end;
|
||||
}
|
||||
|
||||
&[data-show="1"] a {
|
||||
height: @size;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease, height 0.2s step-start;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
position: fixed;
|
||||
bottom: 0.5rem;
|
||||
right: 0.625rem;
|
||||
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.25rem;
|
||||
|
||||
width: @size;
|
||||
height: @size;
|
||||
border-radius: @size;
|
||||
font-size: @font;
|
||||
|
||||
background: var(--accent-bg);
|
||||
color: var(--fg);
|
||||
|
||||
&:hover {
|
||||
background: var(--bg-sec);
|
||||
color: var(--fg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const stt = document.getElementById('scroll-to-top')
|
||||
const doc = document.documentElement
|
||||
|
||||
let scrollPos = 0
|
||||
let ticking = false
|
||||
|
||||
const handler = (pos: number) => {
|
||||
if (pos > doc.clientHeight / 2) {
|
||||
stt.dataset.show = '1'
|
||||
}
|
||||
else {
|
||||
stt.dataset.show = '0'
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('scroll', () => {
|
||||
scrollPos = window.scrollY
|
||||
if (!ticking) {
|
||||
window.requestAnimationFrame(() => {
|
||||
handler(scrollPos)
|
||||
ticking = false
|
||||
})
|
||||
ticking = true
|
||||
}
|
||||
})
|
||||
</script>
|
19
src/content/blog/20220629-mvsp.md
Normal file
19
src/content/blog/20220629-mvsp.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
comments: dcat09/18
|
||||
---
|
||||
|
||||
# Начинающему фронтендеру: margin vs padding
|
||||
|
||||
Раньше я не понимал разницы между margin и padding, и ставил их в CSS наугад, проверяя результат.
|
||||
На StackOverflow объяснение было так себе, да и инглиш я тогда знал тоже так себе.
|
||||
|
||||
Помог мне Chrome, а точнее инструменты разработчика. Внизу вкладки "Стили" есть наглядная визуализация отступов цветными прямоугольниками.
|
||||
|
||||
![](/assets/20220629-mvsp/devtools.jpg)
|
||||
|
||||
- Вокруг содержимого элемента -- **padding**, ограничивающий текст от рамки
|
||||
- После него -- **border**, т.е. сама рамка
|
||||
- После border -- **margin**, ограничивающий элемент от других элементов
|
||||
|
||||
А посмотреть всё это в интерактивном виде можно на [странице на Codeberg Pages](https://darkcat09.codeberg.page/margin-vs-padding).
|
||||
Исходники: [Codeberg](https://codeberg.org/DarkCat09/margin-vs-padding) | [Gitea](https://git.dc09.ru/DarkCat09/margin-vs-padding).
|
28
src/content/blog/20220729-xdt.md
Normal file
28
src/content/blog/20220729-xdt.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
comments: dcat09/37
|
||||
---
|
||||
|
||||
# Технологии XDT, или YouTube всё знает...
|
||||
|
||||
Смотрел я на СТСе Гарри Поттера.
|
||||
На следующий день в рекомендациях ютуба появились видео на тему вышеуказанного фильма, которые я не искал примерно год.
|
||||
Как? Ведь тогда установлены были не официальные сервисы, а MicroG.
|
||||
|
||||
Где-то на хабре в комментах под статьёй то ли про телеметрию, то ли про рекламу, был такой вариант: генерация высокочастотных звуков при трансляции телепередач, чтобы наши девайсы отслеживали их и понимали, что мы смотрим. И на основе этого предлагать таргетированную рекламу.
|
||||
<s>Лишь бы этим не воспользовались. Или уже?</s>
|
||||
|
||||
**Upd:**
|
||||
Технология называется [Cross-device tracking (CDT, XDT)](https://en.m.wikipedia.org/wiki/Cross-device_tracking).
|
||||
К ней относится аналитика, обычно с целью показа рекламы, которая, вместо сохранения идентификатора в одной сессии браузера или его привязки к одному IP-адресу, может передавать рекламный ID между устройствами.
|
||||
Внедряют почти все, кому не лень.
|
||||
|
||||
- Самый простой способ -- отслеживание **залогиненных пользователей**.
|
||||
На сайте у человека есть аккаунт, в который он входит с разных устройств.
|
||||
Таким образом можно сохранять список устройств, далее - делать что угодно.
|
||||
"Рекламный идентификатор" у Google является ярким примером такого XDT.
|
||||
|
||||
- Способ сложнее, о котором я и рассказывал -- **использование ультразвука** для передачи информации между устройствами.
|
||||
Лидирует в этом варианте XDT комания SilverPush, у которой ещё и патент на эту технологию.
|
||||
Для защиты можно использовать приложение [PilferShushJammer](https://github.com/kaputnikGo/PilferShushJammer).
|
||||
|
||||
За информацию большое спасибо [@nvrm17](https://t.me/nvrm17)
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
draft: true
|
||||
comments: dcat09/1
|
||||
---
|
||||
|
||||
|
|
|
@ -4,11 +4,6 @@ comments: dcat09/338
|
|||
|
||||
# Коротко о разработке ПО сейчас
|
||||
|
||||
_[Оригинальный текст](https://factoryfactoryfactory.net)_
|
||||
_Перевод [DarkCat09](https://dc09.ru)_
|
||||
|
||||
***
|
||||
|
||||
Представим, что я решил сделать подставку для специй.
|
||||
|
||||
Я уже имел дело с небольшими проектами по работе с деревом, и хорошо представляю, что мне необходимо: древесный материал и несколько основных инструментов: рулетка, уровень, пила и молоток.
|
||||
|
@ -65,7 +60,7 @@ _Перевод [DarkCat09](https://dc09.ru)_
|
|||
|
||||
— Внимательно слушаю.
|
||||
|
||||
— Когда мы шагнули назад и посмотрели на всю картину инфраструктуры строительных инструментов, мы определили, что люди разочарованы в необходимости управлять фабрикой фабрик, как и производимой ею фабрикой. Что довольно обременительно, когда вы оперируете по такому же сценарию ещё и фабрикой фабрик рулеток, фабрикой фабрик уровней, фабрикой фабрик пил, не говоря уже о холдинге компаний по производству древесного материала. Когда мы здраво оценили ситуацию, мы поняли, что вышеописанное слишком сложно для тех, кому просто хочется сделать подставку для специй.
|
||||
— Когда мы шагнули назад и посмотрели на всю картину инфраструктуры строительных инструментов, мы определили, что люди разочарованы в необходимости управлять фабрикой фабрик, как и производимой ею фабрикой. Это довольно обременительно, когда вы оперируете по такому же сценарию ещё и фабрикой фабрик рулеток, фабрикой фабрик уровней, фабрикой фабрик пил, не говоря уже о холдинге компаний по производству древесного материала. Когда мы здраво оценили ситуацию, мы поняли, что вышеописанное слишком сложно для тех, кому просто хочется сделать подставку для специй.
|
||||
|
||||
— Да, без шуток, абсолютно верно.
|
||||
|
||||
|
@ -84,3 +79,8 @@ _Перевод [DarkCat09](https://dc09.ru)_
|
|||
— Что будет очень полезно для вас!
|
||||
|
||||
— У этой штуки же есть документация, да?
|
||||
|
||||
***
|
||||
|
||||
_[Оригинальный текст](https://factoryfactoryfactory.net) написан Benji Smith,_
|
||||
_переведён [DarkCat09](https://dc09.ru)_
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import Layout from "./Layout.astro";
|
||||
import NavMenu from "./NavMenu.astro";
|
||||
import MenuItem from "../components/MenuItem.astro";
|
||||
import ScrollToTop from "../components/ScrollToTop.astro";
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
|
@ -14,6 +15,7 @@ const { title, description, mainpage = false } = Astro.props;
|
|||
|
||||
<Layout title={"Blog | " + title} description={description}>
|
||||
<slot name="metadata" slot="metadata" />
|
||||
<ScrollToTop />
|
||||
<NavMenu>
|
||||
{
|
||||
mainpage ?
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
---
|
||||
import BlogLayout from "../../layouts/BlogLayout.astro";
|
||||
import ArticleCard from "../../components/ArticleCard.astro";
|
||||
import PageCtrlBtn from "../../components/PageCtrlBtn.astro";
|
||||
|
||||
import { getCollection } from "astro:content";
|
||||
import { Page } from "astro";
|
||||
|
||||
export async function getStaticPaths({ paginate }) {
|
||||
const POSTS_ON_PAGE = 15;
|
||||
|
@ -19,7 +21,7 @@ export async function getStaticPaths({ paginate }) {
|
|||
return paginate(posts, { pageSize: POSTS_ON_PAGE });
|
||||
}
|
||||
|
||||
const { page } = Astro.props;
|
||||
const page: Page = Astro.props.page;
|
||||
const description =
|
||||
"DarkCat09's blog. " +
|
||||
"Reading a QR code without a phone, " +
|
||||
|
@ -35,6 +37,11 @@ const description =
|
|||
<div id="articles">
|
||||
{page.data.map(({ post }) => <ArticleCard post={post} />)}
|
||||
</div>
|
||||
<div id="page-ctrl">
|
||||
<PageCtrlBtn btnKind="prev" url={page.url.prev} />
|
||||
<PageCtrlBtn btnKind="pagenum" num={page.currentPage} />
|
||||
<PageCtrlBtn btnKind="next" url={page.url.next} />
|
||||
</div>
|
||||
</BlogLayout>
|
||||
|
||||
<style lang="less">
|
||||
|
@ -46,4 +53,12 @@ const description =
|
|||
align-items: center;
|
||||
gap: @body-padding + @main-padding;
|
||||
}
|
||||
|
||||
#page-ctrl {
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Add table
Reference in a new issue