CSS Meditation #3: A pseudo is as a pseudo does.
originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
Tips, Expertise, Articles and Advice from the Pro's for Your Website or Blog to Succeed
CSS Meditation #3: A pseudo is as a pseudo does.
originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
Whether you’ve launched a redesign of your website or rolled out a new feature in your app, that is the point where people normally move on to the next project. But, that is a mistake.
It’s only once a site, app, or feature goes live that we get to see actual users interacting with it in a completely natural way. It’s only then that we know if it has succeeded or failed.
Not that things are ever that black and white. Even if it does seem successful, there’s always room for improvement. This is particularly true with conversion rate optimization. Even small tweaks can lead to significant increases in revenue, leads, or other key metrics.
Want to learn more on testing and improving your website? Join Paul Boag in his upcoming live workshop on Fast and Budget-Friendly User Research and Testing, starting July 11.
Making Time for Post-Launch IterationThe key is to build in time for post-launch optimization from the very beginning. When you define your project timeline or sprint, don’t equate launch with the end. Instead, set the launch of the new site, app, or feature about two-thirds of the way through your timeline. This leaves time after launch for monitoring and iteration.
Better still, divide your team’s time into two work streams. One would focus on “innovation” — rolling out new features or content. The second would focus on “optimization” and improving what is already online.
In short, do anything you can to ring-fence at least some time for optimizing the experience post-launch.
Once you’ve done that, you can start identifying areas in your site or app that are underperforming and could do with improvement.
Identifying Problem PointsThis is where analytics can help. Look for areas with high bounce rates or exit points. Users are dropping off at these points. Also, look for low-performing conversion points. But don’t forget to consider this as a percentage of the traffic the page or feature gets. Otherwise, your most popular pages will always seem like the biggest problem.
To be honest, this is more fiddly than it should be in Google Analytics 4, so if you’re not familiar with the platform you might need some help.
Not that Google Analytics is the only tool that can help; I also highly recommend Microsoft Clarity. This free tool provides detailed user data. It includes session recordings and heatmaps. These help you find where to improve on your website or app.
Play particular attention to “insights” which will show you metrics including:
Along with exits and bounces, these metrics indicate that something is wrong and should be looked at in more depth.
Diagnosing The Specific IssuesOnce you’ve found a problem page, the next challenge is diagnosing exactly what’s going wrong.
I tend to start by looking at heat maps of the page that you can find in Clarity or similar tools. These heatmaps will show you where people are engaged on the page and potentially indicate problems.
If that doesn’t help, I will watch recordings of people showing the problem behavior. Watching these session recordings can provide priceless insights. They show the specific pain points users are facing. They can guide you to potential solutions.
If I am still confused about the problem, I may run a survey. I’ll ask users about their experience. Or, I may recruit some people and run usability testing on the page.
Surveys are easier to run, but can be somewhat disruptive and don’t always provide the desired insights. If I do use a survey, I will normally only display it on exit-intent to minimize disruption to the user experience.
If I run usability testing, I favor facilitated testing in this scenario. Although more time-consuming to run, it allows me to ask questions that almost always uncover the problem on the page. Normally, you can get away with only testing with 3 to 6 people.
Once you’ve identified the specific issue, you can then start experimenting with solutions to address it.
Testing Possible SolutionsThere are almost always multiple ways of addressing any given issue, so it’s important to test different approaches to find the best. How you approach this testing will depend on the complexity of your solution.
Sometimes a problem can be fixed with a simple solution involving some UI tweaks or content changes. In this case, you can simply test the variations using A/B testing to see which performs better.
If you haven’t done A/B testing before, it really isn’t that complicated. The only downside is that A/B testing tools are massively overpriced in my opinion. That said, Crazy Egg is more reasonable (although not as powerful) and there is a free tier with VWO.
Using an A/B testing tool starts by setting a goal, like adding an item to the basket. Then, you make versions of the page with your proposed improvement. These are shown to a percentage of visitors.
Making the changes is normally done through a simple WYSIWYG interface and it only takes a couple of minutes.
If your site has lots of traffic, I would encourage you to explore as many possible solutions as possible. If you have a smaller site, focus on testing just a couple of ideas. Otherwise, it will take forever to see results.
Also, with lower-traffic sites, keep the goal as close to the experiment as possible to maximize the amount of traffic. If there’s a big gap between goal and experiment, a lot of people will drop out during the process, and you’ll have to wait longer for results.
Not that A/B testing is always the right way to test ideas. When your solution is more complex, involving new functionality or multiple screens, A/B testing won’t work well. That’s because to A/B test that level of change, you need to effectively build the solution, negating most of the benefits A/B testing provides.
Instead, your best option in such circumstances is to build a prototype that you can test with remote testing.
In the first instance, I tend to run unfacilitated testing using a tool like Maze. Unfacilitated testing is quick to set up, takes little of your time, and Maze will even provide you with analytics on success rates.
But, if unfacilitated testing finds problems and you doubt how to fix them, then consider facilitated testing. That’s because facilitated testing allows you to ask questions and get to the heart of any issues that might arise.
The only drawback of usability testing over A/B testing is recruitment. It can be hard to find the right participants. If that’s the case, consider using a service like Askable, who will carry out recruitment for you for a small fee.
Failing that, don’t be afraid to use friends and family as in most cases getting the exact demographic is less important than you might think. As long as people have comparable physical and cognitive abilities, you shouldn’t have a problem. The only exception is if the content of your website or app is highly specialized.
That said, I would avoid using anybody who works for the organization. They will inevitably be institutionalized and unable to provide unbiased feedback.
Whatever approach you use to test your solution, once you’re happy, you can push that change live for all users. But, your work is still not done.
Rinse And RepeatOnce you’ve solved one issue, return to your analytics. Find the next biggest problem. Repeat the whole process. As you fix some problems, more will become apparent, and so you’ll quickly find yourself with an ongoing program of improvements that can be made.
The more you carry out this kind of work, the more the benefits will become obvious. You will gradually see improvements in metrics like engagement, conversion, and user satisfaction. You can use these metrics to make the case to management for ongoing optimization. This is better than the trap of releasing feature after feature with no regard for their performance.
Meet Fast and Budget-Friendly User Research And TestingIf you are interested in User Research and Testing, check out Paul’s workshop on Fast and Budget-Friendly User Research and Testing, kicking off July 11.
Live workshop with real-life examples.
5h live workshop + friendly Q&A.
Retro fonts are typefaces that imitate and revive the styles of the past. They’re perfect for any design project in which you’re trying to recreate the look of a...
The post The 29 Best Free & Premium Retro Fonts (2024) appeared first on Onextrapixel.
Hi
What is wrong in my this backup code it always not working and gives me an error
SqlConnection con = new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;
AttachDbFilename=D:\repos\mysales\WindowsFormsApp4\Database1.mdf;
Integrated Security=True;
");
string database = con.Database.ToString();
if (textBox1.Text == "")
{
MessageBox.Show("Please Enter Backup File Location");
}
else
{
string cmd = "BACKUP DATABASE [" + database +"] To DISK = '"+ textBox1 .Text + " \\ " +"database"+"-"+ DateTime .Now .ToString ("yyyy-MM-dd--HH-mm-ss") +".bak'";
con.Open();
SqlCommand command=new SqlCommand(cmd, con);
command.ExecuteNonQuery();
MessageBox.Show("Database Backup Done Seccessfully.");
con.Close();
button2.Enabled = false;
}
As we approach International Women in Engineering Day on June 23, 2024, we must recognize women's remarkable achievements and invaluable contributions to engineering.
This global awareness campaign, celebrated annually, aims to highlight the accomplishments of women engineers and encourage more women to pursue careers in this dynamic and impactful industry. In this article, we bring together the insights and experiences of several exceptional women in technology who share their thoughts on the significance of this day and the importance of promoting diversity in the tech industry.
Looking for the scariest websites that will shock you to your core? The internet is full of weird and wonderful things, and there are tons of places to find...
The post 20 Of The Scariest and Nastiest Websites, Games, and Resources appeared first on Onextrapixel.
Prior to the World Wide Web, the act of writing remained consistent for centuries. Words were put on paper, and occasionally, people would read them. The tools might change — quills, printing presses, typewriters, pens, what have you — and an adventurous author may perhaps throw in imagery to compliment their copy.
We all know that the web shook things up. With its arrival, writing could become interactive and dynamic. As web development progressed, the creative possibilities of digital content grew — and continue to grow — exponentially. The line between web writing and web technologies is blurry these days, and by and large, I think that’s a good thing, though it brings its own challenges. As a sometimes-engineer-sometimes-journalist, I straddle those worlds more than most and have grown to view the overlap as the future.
Writing for the web is different from traditional forms of writing. It is not a one-size-fits-all process. I’d like to share the benefits of writing content in digital formats like MDX using a personal project of mine as an example. And, by the end, my hope is to convince you of the greater writing benefits of MDX over more traditional formats.
A Little About MarkdownAt its most basic, MDX is Markdown with components in it. For those not in the know, Markdown is a lightweight markup language created by John Gruber in 2003, and it’s everywhere today. GitHub, Trello, Discord — all sorts of sites and services use it. It’s especially popular for authoring blog posts, which makes sense as blogging is very much the digital equivalent of journaling. The syntax doesn’t “get in the way,” and many content management systems support it.
Markdown’s goal is an “easy-to-read and easy-to-write plain text format” that can readily be converted into XHTML/HTML if needed. Since its inception, Markdown was supposed to facilitate a writing workflow that integrated the physical act of writing with digital publishing.
We’ll get to actual examples later, but for the sake of explanation, compare a block of text written in HTML to the same text written in Markdown.
HTML is a pretty legible format as it is:
<h2>Post Title</h2>
<p>This is an example block of text written in HTML. We can link things up like this, or format the code with <strong>bolding</strong> and <em>italics</em>. We can also make lists of items:</p>
<ul>
<li>Like this item<li>
<li>Or this one</li>
<li>Perhaos a third?</li>
</ul>
<img src="image.avif" alt="And who doesn't enjoy an image every now and then?">
But Markdown is somehow even less invasive:
## Post Title
This is an example block of text written in HTML. We can link things up like this or format the code with **bolding** and *italics*. We can also make lists of items:
- Like this item
- Or this one
- Perhaos a third?
I’ve become a Markdown disciple since I first learned to code. Its clean and relatively simple syntax and wide compatibilities make it no wonder that Markdown is as pervasive today as it is. Having structural semantics akin to HTML while preserving the flow of plain text writing is a good place to be.
However, it could be accused of being a bit too clean at times. If you want to communicate with words and images, you’re golden, but if you want to jazz things up, you’ll find yourself looking further afield for other options.
Gruber set out to create a “format for writing for the web,” and given its ongoing popularity, you have to say he succeeded, yet the web 20 years ago is a long way away from what it is today.
This is the all-important context for what I want to discuss about MDX because MDX is an offshoot of Markdown, only more capable of supporting richer forms of multimedia — and even user interaction. But before we get into that, we should also discuss the concept of web components because that’s the second significant piece that MDX brings to the table.
The move towards richer multimedia websites and apps has led to a thriving ecosystem of web development frameworks and libraries, including React, Vue, Svelte, and Astro, to name a few. The idea that we can have reusable components that are not only interactive but also respond to each other has driven this growth and continues to push on evolving web platform features like web components.
MDX is like a bridge that connects Markdown with modern web tooling. Simply put, MDX weds Markdown’s simplicity with the creative possibilities of modern web frameworks.
By leaning into the overlaps rather than trying to abstract them away at all costs, we find untold potential for beautiful digital content.
My own experience with MDX took shape in a side project of mine: teeline.online. To cut a long story short, before I was a software engineer, I was a journalist, and part of my training involved learning a type of shorthand called Teeline. What it boils down to is ripping out as many superfluous letters as possible — I like to call this process “disemvowelment” — then using Teeline’s alphabet to write the remaining content. This has allowed people like me to write lots of words very quickly.
During my studies, I found online learning resources lacking, so as my engineering skills improved, I started working on the kind of site I’d have used when I was a student if it was available. Hence, teeline.online.
I built the teeling.online site with the Svelte framework for its components. The site’s centerpiece is a dataset of shorthand characters and combinations with which hundreds of outlines can be rendered, combined, and animated as SVG paths.
Likewise, Teeline’s “disemvowelment” script could be wired into a single component that I could then use as many times as I like.
Then, of course, as is only natural when working with components, I could combine them to show the Teeline evolution that converts longhand words into shorthand outlines.
The Markdown, meanwhile, looks as simple as this:
It’s not exactly the sort of complex codebase you might expect for an app. Meanwhile, the files themselves can sit in a nice, tidy directory of their own:
The syllabus is neatly filed away in its own folder. With a bit of metadata sprinkled in, I have everything I need to render an entire section of the site using routing. The setup feels like a fluid medium between worlds. If you want to write with words and pictures, you can. If an idea comes to mind for a component that would better express what you’re going for, you can go make it and drop it in.
In fairness, a “WordToOutline” component like this might not mean much to Teeline newcomers, though with such a clear connection between the Markdown and the rendered pages, it’s not much of a stretch to work out what it is. And, of course, there’s always the likes of services like Storybook that can be used to organize component libraries as they grow.
The raw form of multimedia content can be pretty unsightly — something that needs to be kept at arm’s length by content management systems. With MDX — and its ilk — the content feels rather friendly and legible.
I think you can start to see some of the benefits of an MDX setup like this. There are two key benefits in particulart that I think are worth calling out.
First and foremost, MDX doesn’t distract the writing and editorial flow of working with content. When we’re working with traditional code languages, even HTML, the code format is convoluted with things like opening and closing tags. And it’s even more convoluted if we need the added complexity of embedding components in the content.
MDX (and Markdown, for that matter) is much less verbose. Content is a first-class citizen that takes up way less space than typical markup, making it clear and legible. And where we need the complex affordance of components, those can be dropped in without disrupting that nice editorial experience.
Another key benefit of using MDX is reusability. If, for example, I want to display the same information as images instead, each image would have to be bespoke. But we all know how inefficient it is to maintain content in raster images — it requires making edits in a completely different application, which is highly inconvenient. With an old-school approach, if I update the design of the site, I’m left having to create dozens of images in the new style.
With MDX (or an equivalent like MDsveX), I only need to make the change once, and it updates everywhere. Having done the leg work of building reusable components, I can weave them throughout the syllabus as I see fit, safe in the knowledge that updates will roll out across the board — and do it without affecting the editorial experience whatsoever.
Consider the time it would take to create images or videos representing the same thing. Over time, using fixed assets like images becomes a form of technical — or perhaps editorial — debt that adds up over time, while a multimedia approach that leans into components proves to be faster and more flexible than vanilla methods.
I just made the point that working with reusable components in MDX allows Markdown content to become more robust without affecting the content’s legibility as we author it. Using Svelte’s version of MDX, MDsveX, I was able to combine the clean, readable conventions of Markdown with the rich, interactive potential of components.
It’s only right that all my gushing about MDX and its benefits be tempered with a reality check or two. Like anything else, MDX has its limitations, and your mileage with it will vary.
That said, I believe that those limitations are likely to show up when MDX is perhaps not the best choice for a particular project. There’s a sweet spot that MDX fills and it’s when we need to sprinkle in additional web functionality to the content. We get the best of two worlds: minimal markup and modern web features.
But if components aren’t needed, MDX is overkill when all you need is a clean way to write content that ports nicely into HTML to be consumed by whatever app or platform you use to display it on the web.
Without components, MDX is akin to caring for a skinned elbow with a cast; it’s way more than what’s needed in that situation, and the returns you get from Markdown’s legibility will diminish.
Similarly, if your technical needs go beyond components, you may be looking at a more complex architecture than what MDX can support, and you would be best leaning into what works best for content in the particular framework or stack you’re using.
Code doesn’t age as well as words or images do. An MDX-esque approach does sign you up for the maintenance work of dependency updates, refactoring, and — god forbid — framework migrations. I haven’t had to face the last of those realities yet, though I’d say the first two are well worth it. Indeed, they’re good habits to keep.
Writing with MDX continues to be a learning experience for me, but it’s already made a positive impact on my editorial work.
Specifically, I’ve found that MEX improves the quality of my writing. I think more laterally about how to convey ideas.
Is what I’m saying best conveyed in words, an image, or a data visualization? Perhaps an interactive game?
There is way more potential to enhance my words with componentry than I would get with Markdown alone, opening more avenues for what I can say and how I say it.
Of course, those components do not come for free. MDX does sign you up to build those, regardless of whether you have a set of predefined components included in your framework. At the same time, I’d argue that the opportunities MDX opens up for writing greatly outweigh having to build or maintain a few components.
If MDX had been around in the age of Leonardo Di Vinci, perhaps he may have reached for MDX in his journals. I know I’m taking a great leap of assumption here, but the complexity of what he was writing and trying to describe in technical terms with illustrations would have benefited greatly from MDX for everything from interactive demos of his ideas to a better writing experience overall.
In many respects, MDX’s rich, varied way of approaching content is something that Markdown — and writing for the web in general — encourages already. We don’t think only in terms of words but of links, images, and semantic structure. MDX and its equivalents merely take the lid off the cookie jar so we can enhance our work.
Wouldn’t it be nice if… is a redundant turn of phrase on the web. There may be technical hurdles — or, in my case, skill and knowledge hurdles — but it’s a buzz to think about ways in which your thoughts can best manifest on screen.
At the same time, the simplicity of Markdown is so unintrusive. If someone wants to write content formatted in vanilla Markdown, it’s totally possible to do that without trading up to MDX.
Just having the possibility of bespoke multimedia content is enough to change the creative process. It leaves you using words because you want to, not because you have to.
Why describe the solar system when you can render an explorable one? Why have a picture of a proposed skyscraper when you can display a 3D model? Writing with MDX (or, more accurately, MDsveX) has changed my entire thought process. Potential answers to the question, How do I best get this across?, become more expansive.
Good things happen when worlds collide. New possibilities emerge when seemingly disparate things come together. Many content management systems shield writers — and writing — from code. To my mind, this is like shielding painters from wider color palettes, chefs from exotic ingredients, or sculptors from different types of tools.
Leaning into the overlap between writing and coding gets us closer to one of the web’s great joys: if you can imagine it, you can probably do it.
The value of the Class variable is '0' 'I' '0' 'H' '0' '4'
I hope the value of the Class variable is A' 'T' '0' 'H' '6' '9'
I tried using sort_region to sort SelectedRegions1, but it still didn't work
read_image (Image1, 'C:/Users/29185/Desktop/1.png')
get_image_size (Image1, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
rgb1_to_gray (Image1, GrayImage)
dev_display (GrayImage)
gen_rectangle1 (Rectangle, 59, 49, 89, 159)
reduce_domain (GrayImage, Rectangle, ImageReduced)
threshold (ImageReduced, Regions, 98, 194)
shape_trans (Regions, RegionTrans1, 'rectangle1')
reduce_domain (GrayImage, RegionTrans1, ImageReduced1)
orientation_region (RegionTrans1, Phi)
Phi area_center (RegionTrans1, Area, Row, Column)
vector_angle_to_rigid (Row, Column, rad(180)-Phi, Row, Column,0 , HomMat2D)
Phi>0 , [rad(180)-Phi]
affine_trans_image (Image1, ImageAffineTrans, HomMat2D, 'constant', 'false')
reduce_domain (ImageAffineTrans, RegionTrans1, ImageReduced)
threshold (ImageReduced, Regions1, 100, 215)
connection (Regions1, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions1, 'area', 'and', 89.39, 169.58)
read_ocr_class_mlp ('Industrial_0-9A-Z_NoRej.omc', OCRHandle4)
do_ocr_multi_class_mlp (SelectedRegions1, ImageReduced, OCRHandle4, Class, Confidence)
disp_message (WindowHandle, Class, 'window', 0, 0, 'black', 'true')
A couple of years ago, four JavaScript APIs that landed at the bottom of awareness in the State of JavaScript survey. I took an interest in those APIs because they have so much potential to be useful but don’t get the credit they deserve. Even after a quick search, I was amazed at how many new web APIs have been added to the ECMAScript specification that aren’t getting their dues and with a lack of awareness and browser support in browsers.
That situation can be a “catch-22”:
An API is interesting but lacks awareness due to incomplete support, and there is no immediate need to support it due to low awareness.
Most of these APIs are designed to power progressive web apps (PWA) and close the gap between web and native apps. Bear in mind that creating a PWA involves more than just adding a manifest file. Sure, it’s a PWA by definition, but it functions like a bookmark on your home screen in practice. In reality, we need several APIs to achieve a fully native app experience on the web. And the four APIs I’d like to shed light on are part of that PWA puzzle that brings to the web what we once thought was only possible in native apps.
You can see all these APIs in action in this demo as we go along.
1. Screen Orientation APIThe Screen Orientation API can be used to sniff out the device’s current orientation. Once we know whether a user is browsing in a portrait or landscape orientation, we can use it to enhance the UX for mobile devices by changing the UI accordingly. We can also use it to lock the screen in a certain position, which is useful for displaying videos and other full-screen elements that benefit from a wider viewport.
Using the global screen
object, you can access various properties the screen uses to render a page, including the screen.orientation
object. It has two properties:
type
: The current screen orientation. It can be: "portrait-primary"
, "portrait-secondary"
, "landscape-primary"
, or "landscape-secondary"
.angle
: The current screen orientation angle. It can be any number from 0 to 360 degrees, but it’s normally set in multiples of 90 degrees (e.g., 0
, 90
, 180
, or 270
).On mobile devices, if the angle
is 0
degrees, the type
is most often going to evaluate to "portrait"
(vertical), but on desktop devices, it is typically "landscape"
(horizontal). This makes the type
property precise for knowing a device’s true position.
The screen.orientation
object also has two methods:
.lock()
: This is an async method that takes a type
value as an argument to lock the screen..unlock()
: This method unlocks the screen to its default orientation.And lastly, screen.orientation
counts with an "orientationchange"
event to know when the orientation has changed.
Let’s code a short demo using the Screen Orientation API to know the device’s orientation and lock it in its current position.
This can be our HTML boilerplate:
<main>
<p>
Orientation Type: <span class="orientation-type"></span>
<br />
Orientation Angle: <span class="orientation-angle"></span>
</p>
<button type="button" class="lock-button">Lock Screen</button>
<button type="button" class="unlock-button">Unlock Screen</button>
<button type="button" class="fullscreen-button">Go Full Screen</button>
</main>
On the JavaScript side, we inject the screen orientation type
and angle
properties into our HTML.
let currentOrientationType = document.querySelector(".orientation-type");
let currentOrientationAngle = document.querySelector(".orientation-angle");
currentOrientationType.textContent = screen.orientation.type;
currentOrientationAngle.textContent = screen.orientation.angle;
Now, we can see the device’s orientation and angle properties. On my laptop, they are "landscape-primary"
and 0°
.
If we listen to the window’s orientationchange
event, we can see how the values are updated each time the screen rotates.
window.addEventListener("orientationchange", () => {
currentOrientationType.textContent = screen.orientation.type;
currentOrientationAngle.textContent = screen.orientation.angle;
});
To lock the screen, we need to first be in full-screen mode, so we will use another extremely useful feature: the Fullscreen API. Nobody wants a webpage to pop into full-screen mode without their consent, so we need transient activation (i.e., a user click) from a DOM element to work.
The Fullscreen API has two methods:
Document.exitFullscreen()
is used from the global document object,Element.requestFullscreen()
makes the specified element and its descendants go full-screen.We want the entire page to be full-screen so we can invoke the method from the root element at the document.documentElement
object:
const fullscreenButton = document.querySelector(".fullscreen-button");
fullscreenButton.addEventListener("click", async () => {
// If it is already in full-screen, exit to normal view
if (document.fullscreenElement) {
await document.exitFullscreen();
} else {
await document.documentElement.requestFullscreen();
}
});
Next, we can lock the screen in its current orientation:
const lockButton = document.querySelector(".lock-button");
lockButton.addEventListener("click", async () => {
try {
await screen.orientation.lock(screen.orientation.type);
} catch (error) {
console.error(error);
}
});
And do the opposite with the unlock button:
const unlockButton = document.querySelector(".unlock-button");
unlockButton.addEventListener("click", () => {
screen.orientation.unlock();
});
Yes! We can indeed check page orientation via the orientation
media feature in a CSS media query. However, media queries compute the current orientation by checking if the width is “bigger than the height” for landscape or “smaller” for portrait. By contrast,
The Screen Orientation API checks for the screen rendering the page regardless of the viewport dimensions, making it resistant to inconsistencies that may crop up with page resizing.
You may have noticed how PWAs like Instagram and X force the screen to be in portrait mode even when the native system orientation is unlocked. It is important to notice that this behavior isn’t achieved through the Screen Orientation API, but by setting the orientation
property on the manifest.json
file to the desired orientation type.
Another API I’d like to poke at is the Device Orientation API. It provides access to a device’s gyroscope sensors to read the device’s orientation in space; something used all the time in mobile apps, mainly games. The API makes this happen with a deviceorientation
event that triggers each time the device moves. It has the following properties:
event.alpha
: Orientation along the Z-axis, ranging from 0 to 360 degrees.event.beta
: Orientation along the X-axis, ranging from -180 to 180 degrees.event.gamma
: Orientation along the Y-axis, ranging from -90 to 90 degrees.In this case, we will make a 3D cube with CSS that can be rotated with your device! The full instructions I used to make the initial CSS cube are credited to David DeSandro and can be found in his introduction to 3D transforms.
To rotate the cube, we change its CSS transform
properties according to the device orientation data:
const currentAlpha = document.querySelector(".currentAlpha"); const currentBeta = document.querySelector(".currentBeta"); const currentGamma = document.querySelector(".currentGamma"); const cube = document.querySelector(".cube"); window.addEventListener("deviceorientation", (event) => { currentAlpha.textContent = event.alpha; currentBeta.textContent = event.beta; currentGamma.textContent = event.gamma; cube.style.transform =
rotateX(${event.beta}deg) rotateY(${event.gamma}deg) rotateZ(${event.alpha}deg)
; });
This is the result:
3. Vibration APILet’s turn our attention to the Vibration API, which, unsurprisingly, allows access to a device’s vibrating mechanism. This comes in handy when we need to alert users with in-app notifications, like when a process is finished or a message is received. That said, we have to use it sparingly; no one wants their phone blowing up with notifications.
There’s just one method that the Vibration API gives us, and it’s all we need: navigator.vibrate()
.
vibrate()
is available globally from the navigator
object and takes an argument for how long a vibration lasts in milliseconds. It can be either a number or an array of numbers representing a patron of vibrations and pauses.
navigator.vibrate(200); // vibrate 200ms
navigator.vibrate([200, 100, 200]); // vibrate 200ms, wait 100, and vibrate 200ms.
Let’s make a quick demo where the user inputs how many milliseconds they want their device to vibrate and buttons to start and stop the vibration, starting with the markup:
<main>
<form>
<label for="milliseconds-input">Milliseconds:</label>
<input type="number" id="milliseconds-input" value="0" />
</form>
<button class="vibrate-button">Vibrate</button>
<button class="stop-vibrate-button">Stop</button>
</main>
We’ll add an event listener for a click and invoke the vibrate()
method:
const vibrateButton = document.querySelector(".vibrate-button");
const millisecondsInput = document.querySelector("#milliseconds-input");
vibrateButton.addEventListener("click", () => {
navigator.vibrate(millisecondsInput.value);
});
To stop vibrating, we override the current vibration with a zero-millisecond vibration.
const stopVibrateButton = document.querySelector(".stop-vibrate-button");
stopVibrateButton.addEventListener("click", () => {
navigator.vibrate(0);
});
In the past, it used to be that only native apps could connect to a device’s “contacts”. But now we have the fourth and final API I want to look at: the Contact Picker API.
The API grants web apps access to the device’s contact lists. Specifically, we get the contacts.select()
async method available through the navigator
object, which takes the following two arguments:
properties
: This is an array containing the information we want to fetch from a contact card, e.g., "name"
, "address"
, "email"
, "tel"
, and "icon"
.options
: This is an object that can only contain the multiple
boolean property to define whether or not the user can select one or multiple contacts at a time.I’m afraid that browser support is next to zilch on this one, limited to Chrome Android, Samsung Internet, and Android’s native web browser at the time I’m writing this.
We will make another demo to select and display the user’s contacts on the page. Again, starting with the HTML:
<main>
<button class="get-contacts">Get Contacts</button>
<p>Contacts:</p>
<ul class="contact-list">
<!-- We’ll inject a list of contacts -->
</ul>
</main>
Then, in JavaScript, we first construct our elements from the DOM and choose which properties we want to pick from the contacts.
const getContactsButton = document.querySelector(".get-contacts");
const contactList = document.querySelector(".contact-list");
const props = ["name", "tel", "icon"];
const options = {multiple: true};
Now, we asynchronously pick the contacts when the user clicks the getContactsButton
.
const getContacts = async () => {
try {
const contacts = await navigator.contacts.select(props, options);
} catch (error) {
console.error(error);
}
};
getContactsButton.addEventListener("click", getContacts);
Using DOM manipulation, we can then append a list item to each contact and an icon to the contactList
element.
const appendContacts = (contacts) => { contacts.forEach(({name, tel, icon}) => { const contactElement = document.createElement("li"); contactElement.innerText =
${name}: ${tel}
; contactList.appendChild(contactElement); }); }; const getContacts = async () => { try { const contacts = await navigator.contacts.select(props, options); appendContacts(contacts); } catch (error) { console.error(error); } }; getContactsButton.addEventListener("click", getContacts);
Appending an image is a little tricky since we will need to convert it into a URL and append it for each item in the list.
const getIcon = (icon) => { if (icon.length > 0) { const imageUrl = URL.createObjectURL(icon[0]); const imageElement = document.createElement("img"); imageElement.src = imageUrl; return imageElement; } }; const appendContacts = (contacts) => { contacts.forEach(({name, tel, icon}) => { const contactElement = document.createElement("li"); contactElement.innerText =
${name}: ${tel}
; contactList.appendChild(contactElement); const imageElement = getIcon(icon); contactElement.appendChild(imageElement); }); }; const getContacts = async () => { try { const contacts = await navigator.contacts.select(props, options); appendContacts(contacts); } catch (error) { console.error(error); } }; getContactsButton.addEventListener("click", getContacts);
And here’s the outcome:
Note: The Contact Picker API will only work if the context is secure, i.e., the page is served over https://
or wss://
URLs.
There we go, four web APIs that I believe would empower us to build more useful and robust PWAs but have slipped under the radar for many of us. This is, of course, due to inconsistent browser support, so I hope this article can bring awareness to new APIs so we have a better chance to see them in future browser updates.
Aren’t they interesting? We saw how much control we have with the orientation of a device and its screen as well as the level of access we get to access a device’s hardware features, i.e. vibration, and information from other apps to use in our own UI.
But as I said much earlier, there’s a sort of infinite loop where a lack of awareness begets a lack of browser support. So, while the four APIs we covered are super interesting, your mileage will inevitably vary when it comes to using them in a production environment. Please tread cautiously and refer to Caniuse for the latest support information, or check for your own devices using WebAPI Check.
I have text that is displayed from a database and I have managed to remove the first h3 tag in the text by using the following code but I would also like to remove the two <br> tags that are before the paragraph of text
<h2 class="productsummaryheading mb-0">Product Summary</h2>
<?php
$html= substr($description,0,strrpos(substr($description,0,300)," "));
$final = preg_replace('#<h3>(.*?)</h3>#', '', $html, 1);
echo $final;
?> ...<a href="<?php echo $_SERVER["REQUEST_URI"]; ?>#productdescription">Read More</a>
A example of the text paragraph is below
<br /> <br /> This 11.6 Chromebook is light, portable, rugged, and productive the ultimate everyday learning tool. It brings Google Classroom, G Suite for Education, and todays ...<a href="/shop/laptops-tablets/Laptops/lenovo-100e-chromebook-g2-laptop-11-6-celeron-n4020-4gb-32gb-emmc-webcam-wi-fi-no-lan-usb-c-chrome-os#productdescription">Read More</a>
Have you ever wanted to make bulk updates to your WordPress site?
Wouldn’t it be nice if you could update hundreds of posts with a single click… without having to update them manually?
If you’re like me and most other smart website owners, then you have at least wished for this solution a couple of times in your WordPress journey.
Today, I am excited to announce the new Search & Replace Everything by WPCode, a free tool to easily perform bulk search and replace operations in WordPress.
By default, WordPress does not come with a Find and Replace tool. This makes it hard to do bulk updates on your site.
Especially if you want to quickly update a link on every page, change an image that’s used in multiple areas, or making bulk changes when you’re moving your site.
Website owners either have to update every page manually which is extremely inefficient and time-consuming, or hire a developer to write a SQL query which can be expensive.
And that’s why I decided to create Search & Replace Everything by WPCode.
Search & Replace Everything revolutionizes how you update your content on your site once and for all.
This tool is designed for anyone who manages a WordPress site and wants to save time and avoid errors.
Here are some of the top use cases:
With Search & Replace Everything, our goal is to make it easy to make bulk changes to your website.
Instead of writing complex SQL queries on your own or hiring a developer, you can enter what you want to search for and what you need to replace it with.
Let me show you what makes Search & Replace Everything incredibly powerful yet so simple.
1. Update Everything Quick and Easy
Search & Replace Everything comes with a clean user interface. Just go to the Tools » WP Search & Replace page, enter the content you want to find, and then add the content you want to replace it with.
This simple layout ensures that even non-technical users can perform complex operations without hassle.
2. Control Where to Search
Target your changes precisely by selecting specific database tables or searching across all tables for comprehensive updates.
This feature ensures you’re making changes exactly where needed, preventing any unintended modifications.
3. Precision Search with Case Sensitivity
By default, the plugin performs case-sensitive searches, ensuring accurate and specific matches.
For example, a search for “WordPress” will not match “wordpress” or “WORDPRESS”.
However, if you need to make your searches case-insensitive, you can easily toggle the option. This allows you to find and replace text regardless of its case.
For instance, enabling case-insensitive search would allow “WordPress,” “wordpress,” and “WORDPRESS” to be treated as the same.
4. Preview Before Making Changes
Worried about making mistakes? Preview all the changes before you save them. This feature ensures you get everything right the first time.
5. Replace Any Image in Your Media Library
Replacing images used in multiple places? No problem.
Switch to the ‘Replace Image’ tab, find your image, and click ‘Replace’. It’s that simple.
6. Track & Undo Changes
You can keep track of Search & Replace activity in the ‘History’ tab. This allows you to quickly review the changes you made and undo them with the click of a button.
Note: This feature is available with the paid plan with an introductory $30 discount.
6. Fast, Even on Large Websites
Performing site-wide search and replace operations consumes server resources, which could slow down or crash a website. Search & Replace Everything is designed to be fast and efficient, even if you have a larger website with tons of data.
With Search and Replace Everything, making bulk changes has never been easier.
Search & Replace Everything by WPCode provides an incredibly powerful tool for WordPress site owners.
It makes advanced database search and replacement operations quite simple for all users.
Before performing bulk updates, always create a fresh WordPress database backup. I recommend using Duplicator. It’s an easy way to back up your database and restore it with a single click if needed.
We’re truly building something special here. If you have ideas on how we can make the plugin more helpful to you, please send us your suggestions.
As always, thank you for your continued support of WPBeginner. We look forward to serving you for years to come.
Yours Truly,
Syed Balkhi
Founder of WPBeginner
The post Introducing Search & Replace Everything by WPCode: Bulk Editing in WordPress Made Easy first appeared on WPBeginner.
Hi everyone,
I'm currently facing some challenges while reviewing the SEO report for a website. I've been using a few different tools, but I'm not completely satisfied with the accuracy of the data they provide.
Can anyone recommend the best tool for precise SEO tracking and analysis? I'd love to hear about your experiences and what has worked well for you.
Thanks in advance!
CSS selectors never cease to amaze me in how powerful they can be in matching complex patterns. Most of that flexibility is in parent/child/sibling relationships, very seldomly in value matching. Consider my surprise when I learned that CSS allows matching attribute values regardless off case!
Adding a {space}i
to the attribute selector brackets will make the attribute value search case insensitive:
/* case sensitive, only matches "example" */ [class=example] { background: pink; } /* case insensitive, matches "example", "eXampLe", etc. */ [class=example i] { background: lightblue; }
The use cases for this i
flag are likely very limited, especially if this flag is knew knowledge for you and you’re used to a standard lower-case standard. A loose CSS classname standard will have and would continue to lead to problems, so use this case insensitivity flag sparingly!
The post Case Insensitive CSS Attribute Selector appeared first on David Walsh Blog.
Struggling to keep our inboxes under control and aim for that magical state of inbox zero, the notification announcing an incoming email isn’t the most appreciated sound for many of us. However, there are some emails to actually look forward to: A newsletter, curated and written with love and care, can be a nice break in your daily routine, providing new insights and sparking ideas and inspiration for your work.
With so many wonderful design newsletters out there, we know it can be a challenge to decide which newsletter (or newsletters) to subscribe to. That’s why we want to shine a light on some newsletter gems today to make your decision at least a bit easier — and help you discover newsletters you might not have heard of yet. Ranging from design systems to UX writing, motion design, and user research, there sure is something in it for you.
A huge thank you to everyone who writes, edits, and publishes these newsletters to help us all get better at our craft. You are truly smashing! 👏🏼👏🏽👏🏾
Below you’ll find quick jumps to newsletters on specific topics you might be interested in. Scroll down to browse the complete list or skip the table of contents.
🗓 Delivered every Monday
🖋 Written by Tamas Sari
Aimed at product people, UXers, PMs, and design engineers, the HeyDesigner newsletter is packed with a carefully curated selection of the latest design and front-end articles, tools, and resources.
🗓 Delivered weekly
🖋 Written by Stéphanie Walter
Stéphanie Walter’s Pixels of the Week newsletter keeps you informed about the latest UX research, design, tech (HTML, CSS, SVG) news, tools, methods, and other resources that caught Stéphanie’s interest.
🗓 Delivered daily
🖋 Written by Dan Ni
You’re looking for some bite-sized design inspiration? TLDR Design is a daily newsletter highlighting news, tools, tutorials, trends, and inspiration for design professionals.
🗓 Delivered every two weeks
🖋 Written by Ch'an Armstrong
The DesignOps newsletter provides the DesignOps community with the best hand-picked articles all around design, code, AI, design tools, no-code tools, developer tools, and, of course, design ops.
🗓 Delivered weekly
🖋 Written by Adam Silver
Every week, Adam Silver sends out a newsletter aimed at designers, content designers, and front-end developers. It includes short and sweet, evidence-based design tips, mostly about forms UX, but not always.
🗓 Delivered every Tuesday
🖋 Written by the Smashing Editorial team
Every Tuesday, we publish the Smashing Newsletter with useful tips and techniques on front-end and UX, covering everything from design systems and UX research to CSS and JavaScript. Each issue is curated, written, and edited with love and care, no third-party mailings or hidden advertising.
🗓 Delivered every Monday
🖋 Written by Kenny Chen
UX Design Weekly provides you with a weekly dose of hand-picked user experience design links. Every issue features articles, tools and resources, a UX portfolio, and a quote to spark ideas and get you thinking.
🗓 Delivered weekly
🖋 Written by Fabricio Teixeira and Caio Braga
“Designers are thinkers as much as they are makers.” Following this credo, the UX Collective newsletter helps designers think more critically about their work. Every issue highlights thought-provoking reads, little gems, tools, and resources.
🗓 Delivered every few weeks
🖋 Written by Peter Ramsey
The Built for Mars newsletter brings Peter Ramsey’s UX research straight to your inbox. It includes in-depth UX case studies and bite-sized UX ideas and experiments.
🗓 Delivered weekly
🖋 Written by the Nielsen Norman Group
Studying users around the world, the Nielsen Norman Group provides research-based UX guidance. If you don’t want to miss their latest articles and videos about usability, design, and UX research, you can subscribe to the NN/g newsletter to stay up-to-date.
🗓 Delivered weekly
🖋 Written by Sarah Doody
The UX Notebook Newsletter is aimed at UX and product professionals who want to learn how to apply UX and design principles to design and grow their teams, products, and careers.
🗓 Delivered weekly
🖋 Written by Vitaly Friedman
Every issue of the Smart Interface Design Patterns newsletter is dedicated to a common interface challenge and how to solve it to avoid issues down the line. A treasure chest of design patterns and UX techniques.
🗓 Delivered weekly
🖋 Written by the Interaction Design Foundation
The Interaction Design Foundation is known for their UX courses and webinars for both aspiring designers and advanced professionals. Their UX Weekly newsletter delivers design tips and educational material to help you leverage the power of design.
🗓 Delivered every first Tuesday of a month
🖋 Written by Alex Bilstein
Healthcare systems desparately need UX designers to improve the status quo for both healthcare professionals and patients. The Design With Care newsletter empowers UX designers to create better healthcare experiences and make an impact that matters.
🗓 Delivered every Monday
🖋 Written by Slater Katz
Whether you’re about to start your UX content education or want to get better at UX writing, The UX Gal newsletter is for you. Every Monday, Slater Katz sends out a new newsletter with prompts, thoughts, and exercises to build your UX writing and content design skills.
🗓 Delivered weekly
🖋 Written by the UX Content Collective
The newsletter by the UX Content Collective is perfect for anyone interested in content design. In it, you’ll find curated UX writing resources, new job openings, and exclusive discounts.
🗓 Delivered weekly
🖋 Written by the GatherContent team
The GatherContent newsletter is a weekly email full of content strategy goodies. It features articles, webinars and masterclasses, new books, free templates, and industry news.
🗓 Delivered weekly
🖋 Written by Nikki Anderson
If you want to get more creative and confident when conducting user research, the User Research Academy might be for you. With carefully curated articles, podcasts, events, books, and academic resources all around user research, the newsletter is perfect for beginners and senior UX researchers alike.
🗓 Delivered weekly
🖋 Written by Jan Ahrend
What mattered in UX research this week? To keep you up-to-date on trends, methods, and insights across the UX research industry, Jan Ahrend captures the pulse of the UX research community in his User Weekly newsletter.
🗓 Delivered weekly
🖋 Written by the User Interviews team
The UX Research Newsletter by the folks at User Interviews delivers the latest UX research articles, reports, podcast episodes, and special features. For professional user researchers just like teams who need to conduct user research without a dedicated research team.
🗓 Delivered weekly
🖋 Written by the Baymard Institute
User experience, web design, and e-commerce are the topics which the Baymard Institute newsletter covers. It features ad-free full-length research articles to give you precious insights into the field.
🗓 Delivered every other Sunday
🖋 Written by Chester How, Duncan Leo, and Rick Lee
Whether it’s micro-interactions or easter eggs, Design Spells celebrates the design details that feel like magic and add a spark of delight to a design.
🖋 Written by Justin Volz
Getting you ready for the future of motion design is the goal of Justin Volz’s newsletter. It features UX motion design trends, new UX motion design articles, and more to “make your UI tap dance.”
🗓 Delivered weekly
🖋 Written by Romina Kavcic
Accompanying her interactive step-by-step guide to design systems, Romina Kavcic sends out the weekly Design System Guide newsletter on all things design systems, design process, and design strategy.
🗓 Delivered weekly
🖋 Written by Eugene Fedorenko
The Figmalion newsletter keeps you up-to-date on what is happening in the Figma community, with curated design resources and a weekly roundup of Figma and design tool news.
🗓 Delivered every other Sunday
🖋 Written by Jorge Arango
The Informa(c)tion newsletter explores the intersection of information, cognition, and design. Each issue includes an essay about information architecture and/or personal knowledge management and a list of interesting links.
🗓 Delivered weekly
🖋 Written by Artiom Dashinsky
How about a weekly design challenge to work on your core design skills, improve your portfolio, or prepare for your next job interview? The Weekly Product Design Challenges newsletter has got you covered. Every week, Artiom Dashinsky shares a new exercise inspired and used by companies like Facebook, Google, and WeWork to interview UX design candidates.
🗓 Delivered every other Thursday
🖋 Written by Arkadiusz Radek and Mateusz Litarowicz
With Fundament, Arkadiusz Radek and Mateusz Litarowicz created a place to share what they’ve learned in their ten-year UX and Product Design careers. The newsletter is about the things that matter in design, the practicalities of the job, the lesser-known bits, and content that will help you grow as a UX or Product Designer.
🗓 Delivered weekly
🖋 Written by Jan Haaland
How do people design digital products? With curated UX case studies, the Case Study Club newsletter grants insights into other designers’ processes.
🗓 Delivered monthly
🖋 Written by Trine Falbe
The Ethical Design Network is a space for digital professionals to share, discuss, and self-educate about ethical design. You can sign up to the newsletter to receive monthly news, resources, and event updates all around ethical design.
🗓 Delivered monthly
🖋 Written by Thorsten Jonas
As designers, we have to take responsibility for more than our users. Shining a light on how to design and build more sustainable digital products, the SUX Newsletter by the Sustainable UX Network helps you stand up to that responsibility.
🗓 Delivered weekly
🖋 Written by Ioana Teleanu
A brand-new newsletter on AI, design, and UX goodies comes from Ioana Teleanu: AI Goodies. Every week, it covers the latest resources, trends, news, and tools from the world of AI.
🗓 Delivered weekly
🖋 Written by Alen Faljic
Learning business can help you become a better designer. The d.MBA newsletter is your weekly source of briefings from the business world, hand-picked for the design community by Alen Faljic and the d.MBA team.
🗓 Delivered weekly
🖋 Written by Dan Mall
Tips, tricks, and tools about design systems, process, and leadership, delivered to your inbox every week. That’s the Dan Mall Teaches newsletter.
🗓 Delivered weekly
🖋 Written by Ryan Rumsey
To do things differently, you must look at your work in a new light. That’s the idea behind the Stratatics newsletter. Each week, Ryan Rumsey provides design leaders and executives (and those who work alongside them) with a new idea to reimagine and deliver their best work.
Do you have a favorite newsletter that isn’t featured in the post? Or maybe you’re writing and publishing a newsletter yourself? We’d love to hear about it in the comments below!
Julia Evans has released what she’s saying is one of her most popular zines to date: How Git Works.
I don’t think you’d regret reading it. I imagine most of us get by with knowing just enough Git to do our jobs, but are probably using 5% of what it can really do. Being very strong with Git will almost surely benefit you in your career. Imagine helping a superior out of a sticky situation where it might look like code was lost or otherwise screwed up. Being the solution during an emotional time is clutch. Surely this pairs nicely with Oh Shit, Git!, a real classic from Katie-Sylor Miller which I see has been revitalized with Julia here.
Just the other day here at CodePen Headquarters, I saw a co-worker solve an issue with git bisect
. Have you even heard of that?! Imagine there is a bug in your code, but you have absolutely no idea when it happened or where in the code it might be. That’s not a good feeling, but it’s exactly where git bisect
comes in. As best I understand it, it sets the HEAD of your repo back in time some amount, and there, you test if the bug is present and you can say git bisect good
or git bisect bad
. Then it moves the HEAD and you keep testing and eventually it gets closer and closer to the exact commit (or at least a range of commits) where the bug happened. Then you can look at the changed files in those commits and figure out where in the code the bug may have came from. So cool!
I certainly know developers who know Git and work with it exclusively at the command line entirely as-provided. But I find it more common among the command line types that they at least have some aliases set up for the most common things they do. Those might be their own aliases, like they’ll make gco
do a git checkout
, but it’s worth knowing git itself allows you to make aliases within itself, which could be good since they won’t conflict with anything else. (Have I told you how long I had cp
aliased to move to our local CodePen project directory? 🤣).
A much more elaborate take on git aliases is called Gut. With it, you don’t git commit
anything (with all the params and whatnot you have to also pass), you gut save
which launches a little wizard that asks you questions, and then it does the proper git stuff with the information you give it.
I could see that being great for a beginner, but maybe feel a little too slow as you get more comfortable at the command line. Except when it comes to the more advanced stuff and how it looks designed to get you out of binds. The fix
and undo
commands like awfully helpful and are the kind of things where I can never remember the proper commands.
Paweł Grzybek lays out a classic situation:
Let’s say that we are halfway through the feature, intensely focused on a task, when a critical bug needs to be fixed out of the blue. Happens to us all the time! Should we stash the current changes? Should we quickly smash
git add . && git commit -m "wip"
and promise that we will sort this mess out later?
His answer is no, it’s using git worktrees. It solves the issue by literally making another copy of your project on disk. And you can open and work on it separately but it all goes to the same repo ultimately. So you can leave your half-done uncommitted work on another worktree while you hop to the other to do work. Me, I’m mostly cool with git stash
to tuck stuff away while I go work on something else, or even just the ol “work in progress” or “saving work” commit like Paweł mentioned. It’s not pretty but culturally it’s fine on our project. But I can see how you could get into a groove with worktrees, particularly if your editor supports it nicely.
Phew! We probably talked about Git too much, eh? I know nobody cares. Now let’s go back to just doing the 3-4 commands we know everyday, just with a few more resources in our pocket when we need them.
I gotta leave you with something else. (Digs through bag of hot links.) Ah here we go. This video rules: Flash is dead so I rebuilt it with javascript. Andrew Jakubowicz walks us through building an interface with a pretty modern and lightweight set of tools. Andrew works for Google on Lit, so it’s sort of a big excuse to show off working with Web Components, but it’s a fun ride. At 8 minutes more happens than a typical hour long video.