/* 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 )"
                                 
                                 
                        const newData = Array(20)
      .fill(0)
      .map((_, index) =>  index++);
                                 
                                 
                        // https://levelup.gitconnected.com/what-is-intersection-observer-api-and-how-is-it-useful-1e91a14579df
// https://codepen.io/ohdylan/pen/ZExqKzx
let secondLastChild = document.querySelectorAll('.box:nth-last-child(2)')[0];
let boxes = document.querySelector('.boxes')
const mockFetchMoreBoxes = () => {
    const startIndex = parseInt(secondLastChild.textContent.replace('Test Element', '')) + 2
    for(let i = startIndex; i < startIndex + 20; i++) {
        const newBox = document.createElement('div')
        newBox.textContent = `Test Element ${i}`
        newBox.classList.add('box')
        boxes.append(newBox)
        if(i == startIndex + 18) {
            observer.unobserve(secondLastChild)
            secondLastChild = newBox
            observer.observe(secondLastChild);
        }
    }
}
let observer = new IntersectionObserver((entries) => {
    console.log(entries[0])
    const secondLastChild = entries[0]
    if(secondLastChild.isIntersecting){
        return mockFetchMoreBoxes()
    }
}, {})
observer.observe(secondLastChild);
                                 
                                 
                        /*
https://fatbuddhadesigns.co.uk/journal/full-bleed-layouts/
https://www.joshwcomeau.com/css/full-bleed/
https://blog.logrocket.com/full-bleed-layout-css-grid/
*/
.wrapper {
  display: grid;
  grid-template-columns: 1fr min(60ch, calc(100% - 64px)) 1fr;
  grid-column-gap: 32px;
}
.full-bleed {
  grid-column: 1 / -1;
}
.full-bleed {
  width: 100%;
  grid-column: 1 / 4;
}