export default defineEventHandler(async (event) => {
// Získání dat z externího API pomocí $fetch
const products = await $fetch('https://externi-api.com/products', {
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`
}
})
// Transformace dat na serveru
return products.map(product => ({
id: product.product_id,
title: product.product_name,
price: `${product.price} ${product.currency}`,
inStock: product.stock_quantity > 0
}))
})
// 1
await new Promise(resolve => setTimeout(resolve, 1000)); // wait for 1 sec
// 2
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
<?php
libxml_use_internal_errors(true);
$data = file_get_contents('https://www.psidetektiv.cz/ztracena-zvirata/');
// Load HTML into DOMDocument
$dom = new DOMDocument();
$dom->loadHTML($data, LIBXML_NOERROR | LIBXML_NOWARNING);
$finder = new DomXPath($dom);
$wrapper = $finder->query("//div[@id='category-list']");
if ($wrapper->length > 0) {
$catalogItems = $finder->query(".//div[contains(@class, 'catalog-item')]", $wrapper->item(0));
$savedItems = [];
foreach ($catalogItems as $index => $item) {
// Safely get link
$linkElement = $finder->query(".//a[contains(@href, '/zvire/')]", $item)->item(0);
$link = $linkElement ? $linkElement->getAttribute('href') : '';
// Safely get background image
$bgImageElement = $finder->query(".//span[@class='bg-image']", $item)->item(0);
$bgImageStyle = $bgImageElement ? $bgImageElement->getAttribute('style') : '';
// Extract image URL from style
preg_match('/background-image:url\((.*?)\)/', $bgImageStyle, $matches);
$imageUrl = isset($matches[1]) ? $matches[1] : '';
$name = trim($finder->query(".//div[contains(@class, 'name')]/span[contains(@class, 'label') and contains(text(), 'Jméno:')]/following::text()[1]", $item)->item(0)->nodeValue);
$breed = trim($finder->query(".//div[contains(@class, 'line')]/span[contains(@class, 'label') and contains(text(), 'Plemeno:')]/following::text()[1]", $item)->item(0)->nodeValue);
$lostLocation = trim($finder->query(".//div[contains(@class, 'line')]/span[contains(@class, 'label') and contains(text(), 'Místo ztráty:')]/following::text()[1]", $item)->item(0)->nodeValue);
$region = trim($finder->query(".//div[contains(@class, 'line')]/span[contains(@class, 'label') and contains(text(), 'Kraj:')]/following::text()[1]", $item)->item(0)->nodeValue);
$gender = trim($finder->query(".//div[contains(@class, 'line')]/span[contains(@class, 'label') and contains(text(), 'Pohlaví:')]/following::text()[1]", $item)->item(0)->nodeValue);
$color = trim($finder->query(".//div[contains(@class, 'line')]/span[contains(@class, 'label') and contains(text(), 'Barva:')]/following::text()[1]", $item)->item(0)->nodeValue);
$size = trim($finder->query(".//div[contains(@class, 'line')]/span[contains(@class, 'label') and contains(text(), 'Velikost:')]/following::text()[1]", $item)->item(0)->nodeValue);
$animalData = [
'odkaz' => $link,
'jmeno' => $name,
'plemeno' => $breed,
'misto_ztraty' => $lostLocation,
'kraj' => $region,
'pohlavi' => $gender,
'barva' => $color,
'velikost' => $size,
'obrazek' => $imageUrl
];
$savedItems[] = $animalData;
}
} else {
echo "No elements found\n";
foreach (libxml_get_errors() as $error) {
echo "Line {$error->line}: {$error->message}\n";
}
}
echo "<pre>";
print_r($savedItems);
echo "</pre>";
<!-- https://codepen.io/xqbuilds/pen/LYwvOer -->
<head>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-black text-white flex items-center justify-center min-h-screen space-x-6">
<!-- Hover Dropdown -->
<div class="relative group">
<button class="bg-amber-900 hover:bg-amber-800 px-6 py-3 rounded-lg transition">
Hover Dropdown
</button>
<div class="absolute left-0 hidden w-40 bg-gray-800 rounded-lg group-hover:block">
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option 1</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option 2</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option 3</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option 4</a>
</div>
</div>
<!-- Click Dropdown -->
<div class="relative">
<details>
<summary class="bg-teal-800 hover:bg-teal-700 px-6 py-3 rounded-lg cursor-pointer transition">
Click to Open
</summary>
<div class="absolute left-0 w-40 bg-gray-800 rounded-lg">
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option A</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option B</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option C</a>
<a href="#" class="block px-4 py-2 hover:bg-gray-700">Option D</a>
</div>
</details>
</div>
</body>
</html>
<!-- 1. PROPS -->
<!-- JS -->
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
foo: { type: String, required: true },
bar: Number,
});
// props.foo is a string
// props.bar is a number or undefined
</script>
<!-- TS -->
<script setup lang="ts">
const props = defineProps<{
foo: string;
bar?: number;
}>()
</script>
<script setup lang="ts">
interface Props {
foo: string;
bar?: number;
}
const props = defineProps<Props>()
</script>
<!-- 2. EMITS -->
<!-- JS -->
<script setup>
const emit = defineEmits(['change', 'update'])
</script>
<!-- TS -->
<script setup lang="ts">
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
</script>
<!-- 3. Typing Ref and Reactive Data => Inference -->
<script setup>
import { ref } from 'vue';
const count = ref(0);
count.value = 'string'; // error, inference, we expect number
</script>
<!-- 4. Typing Server Responses -->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface User {
id: number;
name: string;
email: string;
}
const userData = ref<User | null>(null);
onMounted(async () => {
const response = await fetch('https://api.example.com/user');
const data: User = await response.json();
userData.value = data; // TypeScript ensures data usages match the User interface
});
</script>
<!-- 5. Typing Computed Data -->
import { ref, computed } from 'vue'
const count = ref(0)
// inferred type: ComputedRef<number>
const double = computed(() => count.value * 2)
// => TS Error: Property 'split' does not exist on type 'number'
const result = double.value.split('')
// or explicitely define return type
const double = computed<number>(() => {
// type error if this doesn't return a number
})
<!-- 6. Typing Scoped Slots-->
<template>
<slot :msg="message"></slot>
</template>
<script setup lang="ts">
const message = 'Hello, Vue!';
const slots = defineSlots<{
default: (props: { msg: string }) => any;
}>()
</script>
<!-- 7. Typing Template Refs -->
<script setup lang="ts">
import { useTemplateRef, onMounted } from 'vue';
const myInput = useTemplateRef('my-input');
onMounted(() => {
myInput.value?.focus();
});
</script>
<template>
<input ref="my-input" />
</template>
<!-- 8. Typing Provide/Inject -->
<!-- ParentComponent.vue -->
<script setup lang="ts">
import { provide } from 'vue';
const theme = 'dark';
provide('theme', theme);
</script>
<!-- ChildComponent.vue -->
<script setup lang="ts">
import { inject } from 'vue';
const theme = inject<string>('theme'); // Inject with expected type
// TypeScript ensures that 'theme' is of type string
</script>
<!-- 9. Generics -->
<script setup lang="ts" generic="T">
defineProps<{
items: T[]; // Array of items of type T
selected: T; // Single selected item of type T
}>()
</script>
<!-- 10. Typed Composables -->
// useUser.ts
import { ref } from 'vue';
interface User {
id: number;
name: string;
age: number;
}
export function useUser() {
const user = ref<User | null>(null);
function fetchUser(id: number) {
// Fetching user logic
user.value = { id, name: 'John Doe', age: 30 };
}
return { user, fetchUser };
}
<!-- https://www.vuemastery.com/courses/component-design-patterns/one-object-to-rule-them-all -->
<!-- To heavy , to complicated, all props we dont need ...-->
<template>
<main>
<Component
v-for="content in apiResponse"
:key="content.id"
:is="content.type"
:article-title="content.title"
:article-content="content.body"
:ad-image="content.image"
:ad-heading="content.heading"
@click="content.type === 'NewsArticle' ? openArticle : openAd"
@mouseover="content.type === 'NewsArticle' ? showPreview : trackAdEvent"
/>
</main>
</template>
<!--Much better -->
<template>
<main>
<Component
v-for="content in apiResponse"
:key="content.id"
:is="content.type"
v-bind="feedItem(content).attrs"
v-on="feedItem(content).events"
/>
</main>
</template>
<script>
export default {
methods: {
feedItem(item) {
if (item.type === 'NewsArticle') {
return {
attrs: {
'article-title': item.title,
'article-content': item.content
},
events: {
click: this.openArticle,
mouseover: this.showPreview
}
}
} else if (item.type === 'NewsAd') {
return {
attrs: {
'ad-image': item.image,
'ad-heading': item.heading
},
events: {
click: this.openAd,
mouseover: this.trackAdEvent
}
}
}
}
}
}
</script>
/*
https://developer.chrome.com/docs/css-ui/animate-to-height-auto
// 1 moznost, zapnout globalne
:root {
interpolate-size: allow-keywords;
} */
.x {
width: 50px;
overflow: hidden;
background: red;
white-space: nowrap;
transition: 300ms;
}
/*2 nebo pres calc-size */
.x:hover {
width: calc-size(max-content, size);
}
/*
@url https://levelup.gitconnected.com/7-simple-async-await-tricks-for-developers-who-hate-asynchronous-javascript-fe370ac7fe72
*/
// 1. Use Promise.allSettled() for Safer Batch Processing
const results = await Promise.allSettled([
fetchData1(),
fetchData2(),
fetchData3(),
]);
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Success:', result.value);
} else {
console.error('Failed:', result.reason);
}
});
// 2. Use Timeouts to Prevent Hanging Promises
const withTimeout = (promise, ms) =>
Promise.race([
promise,
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms)),
]);
try {
const data = await withTimeout(fetchData(), 5000);
} catch (err) {
console.error(err.message); // "Timeout" if it takes too long
}
// 3. Sequential Loops with Async/Await
const urls = ['url1', 'url2', 'url3'];
for (const url of urls) {
const data = await fetch(url);
console.log(data);
}
// 4. Dynamic Delays with await
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
console.log('Start');
await delay(2000); // Waits 2 seconds
console.log('End');
// 5. Always Use try...catch Inside Async Functions
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Fetch failed');
return await response.json();
} catch (err) {
console.error('Error:', err.message);
return null;
}
}
// 6. await Outside Loops to Batch Workloads
const urls = ['url1', 'url2', 'url3'];
const responses = await Promise.all(urls.map(url => fetch(url)));
const data = await Promise.all(responses.map(res => res.json()));
console.log(data);
// 7 ... fking yield => dont care
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Výběr s Datalist</title>
<script>
function validateInput(input) {
const datalist = document.getElementById('fruit-list');
const options = datalist.getElementsByTagName('option');
const values = Array.from(options).map(option => option.value);
if (!values.includes(input.value)) {
input.value = ''; // Vymaže hodnotu, pokud není v datalistu
}
}
</script>
</head>
<body>
<form>
<label for="fruit">Vyberte ovoce:</label>
<input type="text" id="fruit" name="fruit" list="fruit-list" oninput="validateInput(this)">
<datalist id="fruit-list">
<option value="Jablko">
<option value="Banán">
<option value="Třešně">
<option value="Datle">
</datalist>
<button type="submit">Odeslat</button>
</form>
</body>
</html>
@link https://www.w3.org/TR/wai-aria-1.1/#role_definitions
banner: Hlavní záhlaví stránky.
complementary: Doplňkový obsah.
contentinfo: Informace o obsahu stránky (patička).
main: Hlavní obsah stránky.
navigation: Navigace.
search: Vyhledávací formulář.
article: Samostatný článek nebo příspěvek.
region: Oblast obsahu, která má svůj vlastní význam.
alert: Důležité zprávy nebo upozornění.
dialog: Dialogové okno.
button: Tlačítko.
link: Odkaz.
form: Formulář.
tab: Karta v kartách.
tabpanel: Obsah karty.