#Introduction
Welcome to the my tiny wiki!
This is a place where I keep some of the code snippets that I want to have stored somewhere. If you spot mistakes I'd be glad to here them.
Welcome to the my tiny wiki!
This is a place where I keep some of the code snippets that I want to have stored somewhere. If you spot mistakes I'd be glad to here them.
Nice documentation of a style guide Atlassian
Foundries found:
Check security headers: securityheaders.com
type Modify<T, R> = Omit<T, keyof R> & R
e.g. overwrite children with a more specific type
export type Stack = Modify<Group, { children: Element[] }>
import { readdirSync } from 'fs'
import { defineNuxtModule, addComponentsDir, addImportsDir, createResolver } from '@nuxt/kit'
const featureFolder = 'features'
export default defineNuxtModule({
setup() {
const resolver = createResolver(import.meta.url)
readdirSync(featureFolder).forEach((feature) => {
addComponentsDir({
path: resolver.resolve(`../${featureFolder}/${feature}/components`),
prefix: feature,
})
addImportsDir(resolver.resolve(`../${featureFolder}/${feature}/composables`))
// we don't want feature utils to be imported in the app
// addImportsDir(resolver.resolve(`../${featureFolder}/${feature}/utils`))
})
},
})
define('SSO_CLIENT_ID', '');
define('SSO_CLIENT_SECRET', '');
define('SSO_METADATA', 'https://PROVIDER.COM/.well-known/openid-configuration');
define('SSO_REDIRECT_URI', URL_PUBLIC . 'sso/callback');
public static function action_signin() {
AuthUser::load();
if (AuthUser::isLoggedIn()) {
redirect('/admin');
return;
}
$metadata = self::http(SSO_METADATA);
$_SESSION['state'] = bin2hex(random_bytes(5));
$_SESSION['code_verifier'] = bin2hex(random_bytes(50));
$code_challenge = self::base64_urlencode(hash('sha256', $_SESSION['code_verifier'], true));
$authorize_url = $metadata->authorization_endpoint.'?'.http_build_query([
'response_type' => 'code',
'client_id' => SSO_CLIENT_ID,
'redirect_uri' => SSO_REDIRECT_URI,
'state' => $_SESSION['state'],
'scope' => 'openid email profile',
'code_challenge' => $code_challenge,
'code_challenge_method' => 'S256',
]);
redirect($authorize_url);
}
public static function action_callback() {
if(!isset($_SESSION['state']) || !isset($_GET['state']) || $_SESSION['state'] != $_GET['state']) {
die('Authorization server returned an invalid state parameter');
}
if(isset($_GET['error'])) {
die('Authorization server returned an error: '.htmlspecialchars($_GET['error']));
}
$metadata = self::http(SSO_METADATA);
$response = self::http($metadata->token_endpoint, [
'grant_type' => 'authorization_code',
'code' => $_GET['code'],
'redirect_uri' => SSO_REDIRECT_URI,
'client_id' => SSO_CLIENT_ID,
'client_secret' => SSO_CLIENT_SECRET,
'code_verifier' => $_SESSION['code_verifier'],
]);
if (isset($response->error)) {
die('Authorization server returned an error: '.htmlspecialchars($response->error));
}
$userinfo = self::http($metadata->userinfo_endpoint, [
'access_token' => $response->access_token,
]);
if (!isset($userinfo->sub)) {
die('Error fetching access token');
}
$login = self::createOrLogin($userinfo);
if (!$login) {
die('Authentication request was not successful');
}
redirect('/dashboard');
}
Fade to transparency from a point (center).
export function modAppendFade(shader, background) {
// assumes: https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderLib/meshbasic.glsl.js
shader.vertexShader = shader.vertexShader.replace(
/* glsl */`void main() {`,
/* glsl */`
varying vec4 v_position;
void main() {
v_position = modelMatrix * vec4(position.xyz, 1.0);
`
)
shader.fragmentShader = /* glsl */`
varying vec4 v_position;
${shader.fragmentShader}
`.replace(
/* glsl */`#include <dithering_fragment>`,
/* glsl */`
#include <dithering_fragment>
vec3 center = vec3(0.0, 0.0, 0.0);
vec4 background = vec4(${background || '0.93, 0.93, 0.93, 1.0'});
float diameter = 800.0;
float falloff = 0.006;
float vDistance = distance(v_position.xyz, center);
float factor = clamp((vDistance - diameter) * falloff, 0.0, 1.0);
gl_FragColor = mix(gl_FragColor, background, factor);
`
)
}
node.material.onBeforeCompile = shader => modAppendFade(shader)
node.material.transparent = true
node.material.needsUpdate = true
See Easing Functions Cheat Sheet
function easeInOutCubic(x: number): number {
return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
}
function easeOutElastic(x: number): number {
const c4 = (2 * Math.PI) / 3;
return x === 0
? 0
: x === 1
? 1
: Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
}
function easeInCirc(x: number): number {
return 1 - Math.sqrt(1 - Math.pow(x, 2));
}
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
window.addEventListener('click', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
console.log('Clicked:', intersects[0].object);
}
});
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
}
.carousel > * {
scroll-snap-align: start;
flex: 0 0 auto;
}
function getScrollbarWidth() {
const div = document.createElement('div');
div.style.visibility = 'hidden';
div.style.overflow = 'scroll';
div.style.msOverflowStyle = 'scrollbar'; // for Edge
div.style.width = '50px';
div.style.height = '50px';
document.body.appendChild(div);
const inner = document.createElement('div');
div.appendChild(inner);
const scrollbarWidth = div.offsetWidth - inner.offsetWidth;
div.remove();
return scrollbarWidth;
}
// tailwind 3
// export default {
// plugins: [
// plugin(function ({ addUtilities }) {
addUtilities({
'.appearance-clean': {
'appearance': 'none',
'-moz-appearance': 'textfield',
'&::-webkit-inner-spin-button': {
'-webkit-appearance': 'none',
},
'&::-webkit-outer-spin-button': {
'-webkit-appearance': 'none',
},
},
})
// }),
// ]
// }
/* tailwind v4 */
@layer utils {
.appearance-clean {
appearance: none;
-webkit-appearance: none;
&::-webkit-search-decoration,
&::-webkit-search-cancel-button,
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
}
}
}
<input type="number" class="appearance-clean" />
$ git rm -r --cached .
$ git add --all .
height: calc(100vh + env(safe-area-inset-bottom));
font-display: auto;
font-display: block;
font-display: swap;
font-display: fallback;
font-display: optional;
block-period: renders characters invisible
swap-period: time to swap font-set for an other one
auto
The font display strategy is defined by the user agent.
block
Gives the font face a short block period and an infinite swap period.
swap
Gives the font face an extremely small block period and an infinite swap period.
fallback
Gives the font face an extremely small block period and a short swap period.
optional
Gives the font face an extremely small block period and no swap period.
iOS Safari adds some ugly styling to search inputs. Fixable with:
input {
appearance: none!important;
}
important
because Apple adds them with input[type=search] and therefor has a higher priority.
The swiper needs loop
and speed
.observer
is necessary when the 0 index is wrong.
<swiper
:slides-per-view="'auto'"
:loop="true"
:speed="5000"
:prevent-interaction-on-transition="true"
:observer="true"
:observe-parents="true"
@swiper="onSwiper"
>
<!-- ... -->
</swiper>
Once swiper js is initialized it can be looped.
onSwiper(swiper) {
const loop = () => {
swiper.slideTo(swiper.slides.length - swiper.loopedSlides * 2);
swiper.once('transitionEnd', () => {
swiper.slideTo(0, 0, false);
setTimeout(loop, 0);
});
}
loop();
}
history.replaceState(history.state, undefined, '#hello')
Copy from an input
textarea.select();
document.execCommand('copy');
Copy from a node
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(ELEMENT);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
selection.removeAllRanges();
or
navigator.clipboard.writeText(CONTENT)
const browserTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
@function px($px) { @return round($px * 0.0625rem * 100) / 100; }
@function pt($pt) { @return px($pt * 1.333); }
axios.interceptors.request.use(function (config) {
const token = store.getState().session.token;
config.headers.Authorization = token;
return config;
});
const intersection = array1.filter(element => array2.includes(element));
const sleep = (t: number) => new Promise(r => setTimeout(r, t));
const mod = (n, m) => ((n % m) + m) % m;
as %
(reminder operation) does not work as expected with negative numbers
const map = (value, x1, y1, x2, y2) => ((value - x1) * (y2 - x2)) / (y1 - x1) + x2;
function animate(timing, draw, duration) {
return new Promise((resolve) => {
const start = performance.now();
requestAnimationFrame(function _animate(time) {
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
const progress = timing ? timing(timeFraction) : timeFraction;
draw(progress);
if (timeFraction < 1) {
requestAnimationFrame(_animate);
} else {
resolve();
}
});
});
}
Basic
@font-face {
font-family: "Mechanical";
src: url("mechanical.otf") format("opentype");
}
.ttf format("truetype")
.woff format("woff")
.woff2 format("woff2")
.otf format("opentype")
Vue
@font-face {
font-family: Mechanical;
src: url("~@/assets/fonts/Mechanical.otf") format("opentype");
}
Run PHP inside a Dev-Docker container
$ docker run -it --mount src="$(pwd)",target=/var/www/html,type=bind -p 3000:80 --name phpdev --sysctl net.ipv4.ip_unprivileged_port_start=0 --rm php:7.2-apache /bin/bash -c 'a2enmod rewrite; apache2-foreground'
Different user prevent the easy manipulation of files, it can be solved quite easily with
$ git config core.fileMode false
$ chmod -R 777 .