@import url("https://cdn.jsdelivr.net/npm/comic-mono@0.0.1/index.css");
:root {
font-family: "Comic Sans MS", serif;
}
code {
font-family: "Comic Mono", monospace;
}
h1,
h2 {
margin-block: 0;
}
h1 {
font-size: 14px;
}
h2 {
font-size: 12px;
}
marquee,ge-marquee{
height: calc(100vh - 1lh);
}
.wrapper {
width: 100%;
columns: 4;
}
.wrapper ul {
padding-inline-start: 0;
list-style: none;
font-size: 12px;
}
a, a:link,a:hover,a:visited,a:focus{
color: blue;
}
View Compiled
//import data from "https://unpkg.com/@mdn/browser-compat-data" with { type: "json" };
import "https://unpkg.com/geo-elements@0.0.6/dist/geo-elements.iife.js";
const BCD = await (await fetch("https://unpkg.com/@mdn/browser-compat-data")).json();
const END_DATE = new Date();
const START_DATE = new Date(END_DATE.getFullYear() - 6, 0, 1);
const { browsers, css } = BCD;
const { chrome, safari, firefox } = browsers;
const $a = (node, attrs) => (
Object.entries(Object(attrs)).forEach(([name, value]) =>
node.setAttribute(name, value)
),
node
);
const $c = (node, ...children) => (node.append(...children), node);
const $h = (name, attrs, ...children) =>
$c($a(document.createElement(name), attrs), ...children);
const updateForGMT = (date) => (
date.setTime(date.getTime() + date.getTimezoneOffset() * 60 * 1000), date
);
/** @type Date */
let startDate = updateForGMT(START_DATE);
let endDate = updateForGMT(END_DATE);
const h1 = $h("h1", {}, `CSS Features since ${startDate.getUTCFullYear()}-${(startDate.getUTCMonth() + 1+"").padStart(2, "0")}-${(startDate.getDate()+"").padStart(2,"0")}`)
$c(
document.body,
h1
);
let totalFeatures = 0;
for (const browser of [chrome, safari, firefox]) {
for (const release of Object.values(browser.releases)) {
let { release_date } = release;
if(release_date){
let [YYYY, MM, DD] = release_date.split("-");
release_date = updateForGMT(new Date(+YYYY, MM - 1, +DD));
Object.assign(release, { release_date });
}
}
}
let allSupportedFeatures = {};
for (const [category, features] of Object.entries(css)) {
const featuresEntries = [...Object.entries(features)];
for (const [featureName, feature] of featuresEntries) {
if (!feature?.__compat) {
console.log(featureName, feature);
Object.entries(feature).forEach(([otherName, data]) => {
featuresEntries.push([`${featureName}: ${otherName}`, data]);
});
continue;
}
const {
__compat: {
support: {
chrome: { version_added: chromeVersion },
firefox: { version_added: firefoxVersion },
safari: { version_added: safariVersion }
}
},
...other
} = feature;
Object.entries(other).forEach(([otherName, data]) => {
if (!data?.__compat?.mdn_url) {
data.__compat.mdn_url = feature.__compat.mdn_url;
}
data.__compat.parentName = featureName;
featuresEntries.push([`${featureName}: ${otherName}`, data]);
});
if (!chromeVersion) continue;
if (!firefoxVersion) continue;
if (!safariVersion) continue;
if (!/^\d/.test(chromeVersion)) continue;
if (!/^\d/.test(firefoxVersion)) continue;
if (!/^\d/.test(safariVersion)) continue;
const releaseDates = new Map();
releaseDates.set(
Number(chrome.releases[chromeVersion].release_date),
"chrome " + chromeVersion
);
releaseDates.set(
Number(firefox.releases[firefoxVersion].release_date),
"firefox " + firefoxVersion
);
releaseDates.set(
Number(safari.releases[safariVersion].release_date),
"safari " + safariVersion
);
const firstAvailabilityTime = Math.min(...releaseDates.keys());
const generalAvailabilityTime = Math.max(...releaseDates.keys());
if (generalAvailabilityTime < startDate) continue;
const firstAvailability = new Date(firstAvailabilityTime);
const generalAvailability = new Date(generalAvailabilityTime);
const firstAvailabilityBrowser = releaseDates.get(firstAvailabilityTime);
const generalAvailabilityBrowser = releaseDates.get(
generalAvailabilityTime
);
const year = generalAvailability.getUTCFullYear();
allSupportedFeatures[year] = allSupportedFeatures[year] || {};
allSupportedFeatures[year][category] =
allSupportedFeatures[year][category] || [];
allSupportedFeatures[year][category].push({
category,
feature: featureName,
full: feature,
firstAvailability,
firstAvailabilityBrowser,
generalAvailability,
generalAvailabilityBrowser
});
}
}
console.log(allSupportedFeatures);
const $fragment = $h("div", { class: "wrapper" });
let idx = 0;
for (
let YYYY = startDate.getUTCFullYear();
YYYY <= endDate.getUTCFullYear();
++YYYY
) {
if (!allSupportedFeatures[YYYY]) continue;
let $heading = $h("h2", {}, `${YYYY} - `);
$c($fragment, $heading);
const currentYear = allSupportedFeatures[YYYY];
let currentCategory = "";
let $currentList = null;
$currentList = $h("ul");
let total = 0;
for (const [currentCategory, features] of Object.entries(
Object(currentYear)
)) {
total += features.length;
totalFeatures += features.length;
$c($fragment, $currentList);
features.forEach((feature) => {
const { description: descr, mdn_url, parentName } =
feature?.full?.__compat || {};
let description = $h("code", {}, feature.feature);
if (feature?.full?.__compat?.description) {
description = $h("code");
description.innerHTML = (parentName ? `${parentName}: ` : "") + descr;
}
$c(
$currentList,
$h("li", {}, $h("a", { href: mdn_url, target: "_blank" }, description))
);
});
}
$c($heading, total);
}
h1.textContent += ` (total: ${totalFeatures})`;
const marquee = $h("ge-marquee", {direction:"up", scrollamount:"6", scrolldelay:"60"}, $fragment)
$c(document.body, marquee);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.