// Your personal API key.
// Get it here: https://console.cloud.google.com/google/maps-apis
const API_KEY = '***'
const CALLBACK_NAME = 'gmapsCallback'
let initialized = !!window.google
let resolveInitPromise
let rejectInitPromise
// This promise handles the initialization
// status of the google maps script.
const initPromise = new Promise((resolve, reject) => {
resolveInitPromise = resolve
rejectInitPromise = reject
})
export default function init() {
// If Google Maps already is initialized
// the `initPromise` should get resolved
// eventually.
if (initialized) return initPromise
initialized = true
// The callback function is called by
// the Google Maps script if it is
// successfully loaded.
window[CALLBACK_NAME] = () => resolveInitPromise(window.google)
// We inject a new script tag into
// the `<head>` of our HTML to load
// the Google Maps script.
const script = document.createElement('script')
script.async = true
script.defer = true
script.src = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}&callback=${CALLBACK_NAME}`
script.onerror = rejectInitPromise
document.querySelector('head').appendChild(script)
return initPromise
}
export function debounce(fn, wait){
let timer;
return function(...args){
if(timer) {
clearTimeout(timer); // clear any pre-existing timer
}
const context = this; // get the current context
timer = setTimeout(()=>{
fn.apply(context, args); // call the function if time expires
}, wait);
}
}
export function throttle(fn, wait){
let throttled = false;
return function(...args){
if(!throttled){
fn.apply(this,args);
throttled = true;
setTimeout(()=>{
throttled = false;
}, wait);
}
}
}
export function wait(waitTime, callback = () => {}) {
return new Promise(resolve => {
setTimeout(() => {
callback()
resolve(true)
}, waitTime)
})
}
window.addEventListener('resize', debounce(() => {
console.log('Resized!');
}, 200));
window.addEventListener('scroll', throttle(() => {
console.log('Scrolled!');
}, 200));
/* https://htmixl.medium.com/how-to-create-triangles-in-css-three-easy-ways-49bd6dce7810 */
/* 1. borders */
.triangle{
width: 0;
height: 0;
border-left: 150px solid red;
border-top: 150px solid transparent;
}
/* 2. clip-path */
.triangle{
width: 150px;
height: 150px;
background-color: blue;
clip-path: polygon(0 0, 0 100%, 100% 100%);
}
/* 3. gradient */
.triangle{
width: 150px;
height: 150px;
background-image:
linear-gradient(to top right, green 50%, transparent 0);
background-repeat: no-repeat;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
display: flex;
width: 100%; /* This can be changed via the buttons. */
height: 200px;
padding: 8px;
background: #eaeaea;
}
/* Image Wrappers */
.container > div {
height: 200px;
min-width: 100px;
max-width: 200px;
flex: 1;
background-size: cover;
background-repeat: no-repeat;
}
/* The rest is just setup. */
#app {
display: flex;
flex-direction: column;
align-items: center;
font-family: sans-serif;
padding: 16px;
}
p {
margin-top: 32px;
text-align: center;
color: #4c11f7;
text-transform: uppercase;
font-weight: 600;
font-size: 14px;
letter-spacing: 0.5px;
}
.change-size {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
</style>
</head>
<body>
<div id="app">
<div class="container"></div>
<p>Container Size</p>
<div class="change-size">
<button value="100%">100%</button>
<button value="1400px">1400px</button>
<button value="640px">640px</button>
<button value="200px">200px</button>
</div>
</div>
<script>
/* Attach ResizeObserver to the container. */
const resizeObserver = new ResizeObserver(onResize);
resizeObserver.observe(document.querySelector('.container'));
const IMAGE_MAX_WIDTH = 200;
const IMAGE_MIN_WIDTH = 100;
function onResize(entries) {
const entry = entries[0];
const container = entry.target;
/* Calculate how many images can fit in the container. */
const imagesNeeded = Math.ceil(entry.contentRect.width / IMAGE_MAX_WIDTH);
let images = container.children;
console.log(images);
/* Remove images as needed. */
while (images.length > imagesNeeded) {
images[images.length - 1].remove();
}
/* Add images as needed. */
while (images.length < imagesNeeded) {
let seed = Math.random().toString().replace('.', '');
const newImage = document.createElement('div');
const imageUrl = `https://picsum.photos/seed/${seed}/${IMAGE_MAX_WIDTH}`;
newImage.style.backgroundImage = `url(${imageUrl})`;
container.append(newImage);
}
}
/* The rest is for the container size buttons. */
function changeSize(e) {
if (!e.target.value) return;
const container = document.querySelector('.container');
container.style.width = e.target.value;
}
const changeSizeButtons = document.querySelector('.change-size');
changeSizeButtons.addEventListener('click', changeSize);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
display: flex;
width: 100%; /* This can be changed via the buttons. */
height: 200px;
padding: 8px;
background: #eaeaea;
}
/* Image Wrappers */
.container > div {
height: 200px;
min-width: 100px;
max-width: 200px;
flex: 1;
background-size: cover;
background-repeat: no-repeat;
}
/* The rest is just setup. */
#app {
display: flex;
flex-direction: column;
align-items: center;
font-family: sans-serif;
padding: 16px;
}
p {
margin-top: 32px;
text-align: center;
color: #4c11f7;
text-transform: uppercase;
font-weight: 600;
font-size: 14px;
letter-spacing: 0.5px;
}
.change-size {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
</style>
</head>
<body>
<div id="app">
<div class="container"></div>
<p>Container Size</p>
<div class="change-size">
<button value="100%">100%</button>
<button value="1400px">1400px</button>
<button value="640px">640px</button>
<button value="200px">200px</button>
</div>
</div>
<script>
/* Attach ResizeObserver to the container. */
const resizeObserver = new ResizeObserver(onResize);
resizeObserver.observe(document.querySelector('.container'));
const IMAGE_MAX_WIDTH = 200;
const IMAGE_MIN_WIDTH = 100;
function onResize(entries) {
const entry = entries[0];
const container = entry.target;
/* Calculate how many images can fit in the container. */
const imagesNeeded = Math.ceil(entry.contentRect.width / IMAGE_MAX_WIDTH);
let images = container.children;
console.log(images);
/* Remove images as needed. */
while (images.length > imagesNeeded) {
images[images.length - 1].remove();
}
/* Add images as needed. */
while (images.length < imagesNeeded) {
let seed = Math.random().toString().replace('.', '');
const newImage = document.createElement('div');
const imageUrl = `https://picsum.photos/seed/${seed}/${IMAGE_MAX_WIDTH}`;
newImage.style.backgroundImage = `url(${imageUrl})`;
container.append(newImage);
}
}
/* The rest is for the container size buttons. */
function changeSize(e) {
if (!e.target.value) return;
const container = document.querySelector('.container');
container.style.width = e.target.value;
}
const changeSizeButtons = document.querySelector('.change-size');
changeSizeButtons.addEventListener('click', changeSize);
</script>
</body>
</html>
<!--https://stackoverflow.com/questions/63652288/does-vue-3-teleport-only-works-to-port-outside-vue-->
<template>
<Teleport :to="to" v-if="isMounted"><slot></slot></Teleport>
</template>
<script>
export default {
name: "MountedTeleport",
props: ['to'],
data() {
return {isMounted: false}
},
mounted() {
this.isMounted = true;
}
}
</script>
<!-- https://codepen.io/sandrarodgers/pen/porZbxW -->
<template>
<div id="app">
<div>Height: {{ height }}</div>
<div>Width: {{ width }}</div>
</div>
</template>
<script>
export default {
data() {
return {
debouncedHeight: 0,
debouncedWidth: 0,
heightTimeout: null,
widthTimeout: null
};
},
computed: {
height: {
get() {
return this.debouncedHeight;
},
set(val) {
if (this.timeout) clearTimeout(this.timeout);
this.heightTimeout = setTimeout(() => {
this.debouncedHeight = val;
}, 5000);
}
},
width: {
get() {
return this.debouncedWidth;
},
set(val) {
if (this.timeout) clearTimeout(this.timeout);
this.widthTimeout = setTimeout(() => {
this.debouncedWidth = val;
}, 5000);
}
},
},
methods: {
resizeHandler(e) {
this.height = window.innerHeight;
this.width = window.innerWidth;
},
},
mounted() {
this.height = window.innerHeight;
this.width = window.innerWidth;
},
created() {
window.addEventListener("resize", this.resizeHandler);
},
destroyed() {
window.removeEventListener("resize", this.resizeHandler);
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
font-size: 1.5rem;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<?php
trait FastAdminLastChangeTrait {
/**
* Bootstrap trait
*
* @return void
*/
public function injectFastAdminLastChangeTrait()
{
$this->onBeforeSave[] = function($editRow, $values, $form) {
$values['lastchange'] = new \DateTime();
$values['lastchange__user_id'] = $this->getUser()->getId();
};
$this->onCreateForm[] = function($form)
{
if(isset($form['lastchange']))
$form['lastchange']->getControlPrototype()->addClass('deactivateInput');
if(isset($form['lastchange__user_id']))
$form['lastchange__user_id']->getControlPrototype()->addClass('deactivateInput');
};
}
}
// https://css-tricks.com/linearly-scale-font-size-with-css-clamp-based-on-the-viewport/#for-those-who-dont-mind-that-edge-case
// https://royalfig.github.io/fluid-typography-calculator/
// https://fluid-typography.netlify.app/
function clampBuilder( minWidthPx, maxWidthPx, minFontSize, maxFontSize ) {
const root = document.querySelector( "html" );
const pixelsPerRem = Number( getComputedStyle( root ).fontSize.slice( 0,-2 ) );
const minWidth = minWidthPx / pixelsPerRem;
const maxWidth = maxWidthPx / pixelsPerRem;
const slope = ( maxFontSize - minFontSize ) / ( maxWidth - minWidth );
const yAxisIntersection = -minWidth * slope + minFontSize
return `clamp( ${ minFontSize }rem, ${ yAxisIntersection }rem + ${ slope * 100 }vw, ${ maxFontSize }rem )`;
}
console.log(clampBuilder(320, 1920, 1, 3)); // "clamp( 1rem, 0.6rem + 2vw, 3rem )"