Initial commit: MVP+ wish board with FastAPI + Tailwind

This commit is contained in:
Nikita committed 2026-08-05 17:06:36 +05:00
commit cd945a6128
2277 files changed
+843095

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Alex Reardon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+290
View File
@@ -0,0 +1,290 @@
# `css-box-model` 📦
Get accurate and well named [CSS Box Model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model) information about a [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element).
[![Build Status](https://travis-ci.org/alexreardon/css-box-model.svg?branch=master)](https://travis-ci.org/alexreardon/css-box-model)
[![npm](https://img.shields.io/npm/v/css-box-model.svg)](https://www.npmjs.com/package/css-box-model)
[![dependencies](https://david-dm.org/alexreardon/css-box-model.svg)](https://david-dm.org/alexreardon/css-box-model)
[![Downloads per month](https://img.shields.io/npm/dm/css-box-model.svg)](https://www.npmjs.com/package/css-box-model)
[![min](https://img.shields.io/bundlephobia/min/css-box-model.svg)](https://www.npmjs.com/package/css-box-model)
[![minzip](https://img.shields.io/bundlephobia/minzip/css-box-model.svg)](https://www.npmjs.com/package/css-box-model)
Any time you are using [`Element.getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) you might want to consider using `css-box-model` instead to get more detailed box model information.
## Usage
```js
// @flow
import { getBox } from 'css-box-model';
const el: HTMLElement = document.getElementById('foo');
const box: BoxModel = getBox(el);
// profit
```
## Installation
```bash
## yarn
yarn add css-box-model
# npm
npm install css-box-model --save
```
## The [CSS Box Model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model)
![the box model](https://user-images.githubusercontent.com/2182637/46847224-f8a23e80-ce2e-11e8-80d6-0ca62a1871a7.png)
| Box type | Composition |
| ----------- | ----------------------------------- |
| Margin box | margin + border + padding + content |
| Border box | border + padding + content |
| Padding box | padding + content |
| Content box | content |
This our returned `BoxModel`:
```js
export type BoxModel = {|
// content + padding + border + margin
marginBox: Rect,
// content + padding + border
borderBox: Rect,
// content + padding
paddingBox: Rect,
// content
contentBox: Rect,
// for your own consumption
border: Spacing,
padding: Spacing,
margin: Spacing,
|};
// Supporting types
// This is an extension of DOMRect and ClientRect
export type Rect = {|
// ClientRect
top: number,
right: number,
bottom: number,
left: number,
width: number,
height: number,
// DOMRect
x: number,
y: number,
// Rect
center: Position,
|};
export type Position = {|
x: number,
y: number,
|};
export type Spacing = {
top: number,
right: number,
bottom: number,
left: number,
};
```
## API
### `getBox`
> (el: HTMLElement) => BoxModel
Use `getBox` to return the box model for an element
### `withScroll`
> `(original: BoxModel, scroll?: Position = getWindowScroll()) => BoxModel`
This is useful if you want to know the box model for an element relative to a page
```js
const el: HTMLElement = document.getElementById('app');
const box: BoxModel = getBox(el);
const withScroll: BoxModel = withScroll(box);
```
You are welcome to pass in your own `scroll`. By default we we use the window scroll:
```js
const getWindowScroll = (): Position => ({
x: window.pageXOffset,
y: window.pageYOffset,
});
```
### `calculateBox`
> `(borderBox: AnyRectType, styles: CSSStyleDeclaration) => BoxModel`
This will do the box model calculations without needing to read from the DOM. This is useful if you have already got a `ClientRect` / `DOMRect` and a `CSSStyleDeclaration` as then we can skip computing these values.
```js
const el: HTMLElement = document.getElementById('app');
const borderBox: ClientRect = el.getBoundingClientRect();
const styles: CSSStyleDeclaration = window.getComputedStyles(el);
const box: BoxModel = calculateBox(borderBox, styles);
```
**`AnyRectType`** allows for simple interoperability with any rect type
```js
type AnyRectType = ClientRect | DOMRect | Rect | Spacing;
```
### `createBox`
> `({ borderBox, margin, border, padding }: CreateBoxArgs) => BoxModel`
Allows you to create a `BoxModel` by passing in a `Rect` like shape (`AnyRectType`) and optionally your own `margin`, `border` and or `padding`.
```js
type CreateBoxArgs = {|
borderBox: AnyRectType,
margin?: Spacing,
border?: Spacing,
padding?: Spacing,
|};
```
```js
const borderBox: Spacing = {
top: 10,
right: 100,
left: 20,
bottom: 80,
};
const padding: Spacing = {
top: 10,
right: 20,
left: 20,
bottom: 10,
};
const box: BoxModel = createBox({ borderBox, padding });
```
## Utility API
> Functions to help you interact with the objects we provide
### `getRect`
> `(spacing: AnyRectType) => Rect`
Given any `Rect` like shape, return a `Rect`. Accepts any object that has `top`, `right`, `bottom` and `right` (eg `ClientRect`, `DOMRect`);
```js
const spacing: Spacing = {
top: 0,
right: 100,
bottom: 50,
left: 50,
};
const rect: Rect = getRect(spacing);
console.log(rect);
/*
{
top: 0,
right: 100,
bottom: 50,
left: 50,
width: 100,
height: 50,
x: 0,
y: 0,
center: { x: 50, y: 50 },
}
*/
```
### `expand`
Used to expand a `Spacing`
```js
(target: Spacing, expandBy: Spacing) => Spacing;
```
```js
const original: Spacing = {
top: 10,
left: 11,
right: 21,
bottom: 22,
};
const expandBy: Spacing = {
top: 1,
left: 2,
right: 3,
bottom: 4,
};
const expanded: Spacing = expand(original, expandBy);
console.log(expanded);
/*
{
// pulled back
top: 8,
left: 8
// pushed forward
bottom: 22,
right: 22,
}
*/
```
### `shrink`
Used to shrink a `Spacing`
```js
(target: Spacing, shrinkBy: Spacing) => Spacing;
```
```js
const original: Spacing = {
top: 10,
left: 10,
right: 20,
bottom: 20,
};
const shrinkBy: Spacing = {
top: 2,
left: 2,
right: 2,
bottom: 2,
};
const smaller: Spacing = shrink(original, shrinkBy);
console.log(smaller);
/*
{
// pushed forward
top: 12,
left: 12
// pulled back
bottom: 18,
right: 18,
}
*/
```
+61
View File
@@ -0,0 +1,61 @@
{
"name": "css-box-model",
"version": "1.2.1",
"description": "Get accurate and well named css box model information about an Element 📦",
"author": "Alex Reardon <alexreardon@gmail.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/alexreardon/css-box-model.git"
},
"bugs": {
"url": "https://github.com/alexreardon/css-box-model/issues"
},
"keywords": [
"css",
"box model",
"css box model",
"getBoundingClientRect",
"DOMRect",
"ClientRect",
"Rect",
"Spacing",
"DOM"
],
"files": [
"/dist",
"/src"
],
"main": "dist/css-box-model.cjs.js",
"module": "dist/css-box-model.esm.js",
"types": "src/index.d.ts",
"sideEffects": false,
"scripts": {
"test": "yarn jest",
"lint": "yarn prettier --debug-check src/** test/**",
"validate": "yarn lint && flow check",
"build:clean": "rimraf dist",
"build:flow": "echo \"// @flow\n\nexport * from '../src';\" > dist/css-box-model.cjs.js.flow",
"build:dist": "yarn rollup --config rollup.config.js",
"build": "yarn build:clean && yarn build:dist && yarn build:flow",
"prepublishOnly": "yarn build"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-flow": "^7.0.0",
"babel-plugin-dev-expression": "^0.2.2",
"flow-bin": "0.106.1",
"jest": "^24.9.0",
"prettier": "1.18.2",
"rimraf": "^3.0.0",
"rollup": "^1.20.2",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-terser": "^5.1.1"
},
"dependencies": {
"tiny-invariant": "^1.0.6"
}
}
+59
View File
@@ -0,0 +1,59 @@
declare module 'css-box-model' {
export type Position = {
x: number;
y: number;
};
export type Rect = {
top: number;
right: number;
bottom: number;
left: number;
width: number;
height: number;
x: number;
y: number;
center: Position;
};
export type BoxModel = {
marginBox: Rect;
borderBox: Rect;
paddingBox: Rect;
contentBox: Rect;
border: Spacing;
padding: Spacing;
margin: Spacing;
};
export type AnyRectType = ClientRect | DOMRect | Rect | Spacing;
export type Spacing = {
top: number;
right: number;
bottom: number;
left: number;
};
export const getRect: ({ top, right, bottom, left }: Spacing) => Rect;
export const expand: (target: Spacing, expandBy: Spacing) => Spacing;
export const shrink: (target: Spacing, shrinkBy: Spacing) => Spacing;
type CreateBoxArgs = {
borderBox: AnyRectType;
margin?: Spacing;
border?: Spacing;
padding?: Spacing;
};
export const createBox: (boxArgs: CreateBoxArgs) => BoxModel;
export const offset: (original: BoxModel, change: Position) => BoxModel;
export const withScroll: (original: BoxModel, scroll?: Position) => BoxModel;
export const calculateBox: (
borderBox: AnyRectType,
styles: CSSStyleDeclaration,
) => BoxModel;
export const getBox: (el: Element) => BoxModel;
}
+243
View File
@@ -0,0 +1,243 @@
// @flow
import invariant from 'tiny-invariant';
// # The CSS box model
// > https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model
//
// ------------------------------------
// | MARGIN | (marginBox)
// | ------------------------------ |
// | | BORDER | | (borderBox)
// | | ------------------------ | |
// | | | PADDING | | | (paddingBox) - not used by anything really
// | | | ------------------ | | |
// | | | | CONTENT | | | | (contentBox)
// | | | | | | | |
// | | | | | | | |
// | | | | | | | |
// | | | ------------------ | | |
// | | | | | |
// | | ------------------------ | |
// | | | |
// | ------------------------------ |
// | |
// | ----------------------------------|
export type Position = {|
x: number,
y: number,
|};
export type Rect = {|
top: number,
right: number,
bottom: number,
left: number,
width: number,
height: number,
x: number,
y: number,
center: Position,
|};
export type BoxModel = {|
// content + padding + border + margin
marginBox: Rect,
// content + padding + border
borderBox: Rect,
// content + padding
paddingBox: Rect,
// content
contentBox: Rect,
// for your own consumption
border: Spacing,
padding: Spacing,
margin: Spacing,
|};
export type AnyRectType = ClientRect | DOMRect | Rect | Spacing;
export type Spacing = {
top: number,
right: number,
bottom: number,
left: number,
};
export const getRect = ({ top, right, bottom, left }: Spacing): Rect => {
const width: number = right - left;
const height: number = bottom - top;
const rect: Rect = {
// ClientRect
top,
right,
bottom,
left,
width,
height,
// DOMRect
x: left,
y: top,
// Rect
center: {
x: (right + left) / 2,
y: (bottom + top) / 2,
},
};
return rect;
};
export const expand = (target: Spacing, expandBy: Spacing): Spacing => ({
// pulling back to increase size
top: target.top - expandBy.top,
left: target.left - expandBy.left,
// pushing forward to increase size
bottom: target.bottom + expandBy.bottom,
right: target.right + expandBy.right,
});
export const shrink = (target: Spacing, shrinkBy: Spacing): Spacing => ({
// pushing forward to decrease size
top: target.top + shrinkBy.top,
left: target.left + shrinkBy.left,
// pulling backwards to decrease size
bottom: target.bottom - shrinkBy.bottom,
right: target.right - shrinkBy.right,
});
const shift = (target: Spacing, shiftBy: Position): Spacing => ({
top: target.top + shiftBy.y,
left: target.left + shiftBy.x,
bottom: target.bottom + shiftBy.y,
right: target.right + shiftBy.x,
});
const noSpacing: Spacing = {
top: 0,
right: 0,
bottom: 0,
left: 0,
};
type CreateBoxArgs = {|
borderBox: AnyRectType,
margin?: Spacing,
border?: Spacing,
padding?: Spacing,
|};
export const createBox = ({
borderBox,
margin = noSpacing,
border = noSpacing,
padding = noSpacing,
}: CreateBoxArgs): BoxModel => {
// marginBox = borderBox + margin
const marginBox: Rect = getRect(expand(borderBox, margin));
// borderBox = borderBox - padding
const paddingBox: Rect = getRect(shrink(borderBox, border));
// contentBox = paddingBox - padding
const contentBox: Rect = getRect(shrink(paddingBox, padding));
return {
marginBox,
borderBox: getRect(borderBox),
paddingBox,
contentBox,
margin,
border,
padding,
};
};
// Computed spacing styles will always be in pixels
// https://codepen.io/alexreardon/pen/OZyqXe
const parse = (raw: string): number => {
const value: string = raw.slice(0, -2);
const suffix: string = raw.slice(-2);
// ## Used values vs computed values
// `getComputedStyle` will return the * used values * if the
// element has `display: none` and the *computed values* otherwise
// *used values* can include 'rem' etc.
// Rather than throwing we are returning `0`.
// Given that the element is _not visible_ it takes up no visible space and so `0` is correct
// ## `jsdom`
// The `raw` value can also not be populated in jsdom
if (suffix !== 'px') {
return 0;
}
const result: number = Number(value);
invariant(
!isNaN(result),
`Could not parse value [raw: ${raw}, without suffix: ${value}]`,
);
return result;
};
const getWindowScroll = (): Position => ({
x: window.pageXOffset,
y: window.pageYOffset,
});
export const offset = (original: BoxModel, change: Position): BoxModel => {
const { borderBox, border, margin, padding } = original;
const shifted: Spacing = shift(borderBox, change);
return createBox({
borderBox: shifted,
border,
margin,
padding,
});
};
export const withScroll = (
original: BoxModel,
scroll?: Position = getWindowScroll(),
): BoxModel => offset(original, scroll);
// Exposing this function directly for performance. If you have already computed these things
// then you can simply pass them in
export const calculateBox = (
borderBox: AnyRectType,
styles: CSSStyleDeclaration,
): BoxModel => {
const margin: Spacing = {
top: parse(styles.marginTop),
right: parse(styles.marginRight),
bottom: parse(styles.marginBottom),
left: parse(styles.marginLeft),
};
const padding: Spacing = {
top: parse(styles.paddingTop),
right: parse(styles.paddingRight),
bottom: parse(styles.paddingBottom),
left: parse(styles.paddingLeft),
};
const border: Spacing = {
top: parse(styles.borderTopWidth),
right: parse(styles.borderRightWidth),
bottom: parse(styles.borderBottomWidth),
left: parse(styles.borderLeftWidth),
};
return createBox({
borderBox,
margin,
padding,
border,
});
};
export const getBox = (el: Element): BoxModel => {
// getBoundingClientRect always returns the borderBox
const borderBox: ClientRect = el.getBoundingClientRect();
const styles: CSSStyleDeclaration = window.getComputedStyle(el);
return calculateBox(borderBox, styles);
};