squiggles
@@ -65,9 +65,14 @@ namespace TerribleDev.Blog.Web.Controllers
|
||||
{
|
||||
return Redirect($"/404/?from=/{postUrl}/{amp}/");
|
||||
}
|
||||
this.ViewData["amp"] = amp == "amp";
|
||||
var isAmp = amp == "amp";
|
||||
this.ViewData["amp"] = isAmp;
|
||||
if(postCache.UrlToPost.TryGetValue(postUrl, out var currentPost))
|
||||
{
|
||||
if(isAmp && !currentPost.isAmp)
|
||||
{
|
||||
return Redirect($"/{postUrl}/");
|
||||
}
|
||||
return View("Post", model: new PostViewModel() { Post = currentPost });
|
||||
}
|
||||
if(postCache.LandingPagesUrl.TryGetValue(postUrl, out var landingPage))
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace TerribleDev.Blog.Web.Controllers
|
||||
Urls = postCache.PostsAsLists.Select(a => new SiteMapItem() { LastModified = DateTime.UtcNow, Location = a.CanonicalUrl }).ToList()
|
||||
};
|
||||
sitemap.Urls.AddRange(sitewideLinks);
|
||||
sitemap.Urls.AddRange(postCache.PostsAsLists.Select(a => new SiteMapItem() { LastModified = DateTime.UtcNow, Location = a.AMPUrl }).ToList());
|
||||
sitemap.Urls.AddRange(postCache.PostsAsLists.Where(i => i.isAmp).Select(a => new SiteMapItem() { LastModified = DateTime.UtcNow, Location = a.AMPUrl }).ToList());
|
||||
ser.Serialize(this.Response.Body, sitemap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,9 @@ namespace TerribleDev.Blog.Web
|
||||
JsonLDBreadcrumbString = breadcrumb.ToHtmlEscapedString().Replace("https://schema.org", "https://schema.org/true"),
|
||||
HasCode = hasCode
|
||||
};
|
||||
|
||||
var thumbNailUrl = string.IsNullOrWhiteSpace(postSettings.thumbnailImage) ?
|
||||
postImages?.FirstOrDefault() ?? "https://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061?s=640" :
|
||||
$"{canonicalUrl}/{postSettings.thumbnailImage}";
|
||||
return new Post()
|
||||
{
|
||||
PublishDate = postSettings.date.ToUniversalTime(),
|
||||
@@ -137,7 +139,9 @@ namespace TerribleDev.Blog.Web
|
||||
AMPUrl = ampUrl,
|
||||
UrlWithoutPath = resolvedUrl,
|
||||
isLanding = postSettings.isLanding,
|
||||
Content = content
|
||||
Content = content,
|
||||
isAmp = postSettings.isAmp,
|
||||
ThumbnailImage = thumbNailUrl,
|
||||
};
|
||||
}
|
||||
private async Task<LandingPage> BuildLandingPage(string fileName, string domain, string markdownText, PostSettings postSettings, string resolvedUrl, string canonicalUrl, string ampUrl)
|
||||
@@ -184,7 +188,8 @@ namespace TerribleDev.Blog.Web
|
||||
AMPUrl = ampUrl,
|
||||
UrlWithoutPath = resolvedUrl,
|
||||
isLanding = postSettings.isLanding,
|
||||
Content = content
|
||||
Content = content,
|
||||
isAmp = postSettings.isAmp
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace TerribleDev.Blog.Web.Models
|
||||
DateTime? UpdatedDate { get; set; }
|
||||
IPostContent Content { get; set; }
|
||||
bool isLanding { get; set; }
|
||||
bool isAmp { get; set; }
|
||||
string ThumbnailImage { get; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,5 +19,7 @@ namespace TerribleDev.Blog.Web.Models
|
||||
public IPostContent Content { get; set; }
|
||||
|
||||
public bool isLanding { get; set; } = false;
|
||||
public bool isAmp { get; set; } = true;
|
||||
public string ThumbnailImage { get => "https://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061?s=640"; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,5 +20,8 @@ namespace TerribleDev.Blog.Web.Models
|
||||
public IPostContent Content { get; set; }
|
||||
|
||||
public bool isLanding { get; set; } = false;
|
||||
public bool isAmp { get; set; } = true;
|
||||
|
||||
public string ThumbnailImage { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,5 +17,7 @@ namespace TerribleDev.Blog.Web.Models
|
||||
public string layout { get; set; }
|
||||
|
||||
public bool isLanding { get; set; } = false;
|
||||
|
||||
public bool isAmp { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
title: Dynamically changing the site-theme meta tag
|
||||
date: 2022-04-12 11:05
|
||||
isAmp: false
|
||||
thumbnailImage: 1.jpg
|
||||
tags:
|
||||
- javascript
|
||||
- js
|
||||
- react
|
||||
---
|
||||
|
||||
So, incase you are unfamiliar, there is a meta tag called `<meta name="theme-color" content="...">` that is used to change the color of the navbar on desktop safari, mobile safari, and mobile chrome. If you don't set a value these browsers tend to find a color that match the site to the best of their ability. However, sometimes even setting the value can cause the site to look ugly.
|
||||
|
||||
<!-- more -->
|
||||
|
||||
So, I've been recently working on an NFT project called [Squiggle Squatches](http://squigglesquatches.io/). NFT projects are essentially digital art projects for sale. Our website, really needs to reflect our look and feel as much as we can. When I first loaded our page, I noticed this **huge** white bar on the top of Safari.
|
||||
|
||||

|
||||
|
||||
|
||||
> So I set out to change this. I knew there was a `<meta name="theme-color" content="...">` tag that can add the theme.
|
||||
|
||||
I first made the theme be the color of the top section, and this looked great!
|
||||
|
||||

|
||||
|
||||
However after scrolling, I noticed this looked super ugly.
|
||||
|
||||

|
||||
|
||||
So I decided to write some code to fix this problem.
|
||||
|
||||
## Listening to scroll events
|
||||
|
||||
So, I started with decorating certain tags with a `data-scroll-theme` attribute that signaled our code to look at this div to manipulate the theme color. This looks like `<section data-scroll-theme class="blue/red/etc">content</section>`
|
||||
|
||||
I then ended up crafting this JS code. Basically, make a throttle function so we only fire our event every 100ms. Grab the default color. Then on scroll figure out if any boxes are at the top of the page, and if so set the meta tag to that color.
|
||||
|
||||
```js
|
||||
// a function to only call the wrapped functions every x milliseconds so the scroll event doesn't make our function run all the time
|
||||
function throttle(func, timeFrame) {
|
||||
var lastTime = 0;
|
||||
return function(...args) {
|
||||
var now = new Date().getTime();
|
||||
if (now - lastTime >= timeFrame) {
|
||||
func(...args);
|
||||
lastTime = now;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// get the theme color on load so we can revert to this
|
||||
const ogColor = document.querySelector('meta[name="theme-color"]')?.getAttribute('content');
|
||||
|
||||
// handle scroll event
|
||||
const handleScroll = throttle(() => {
|
||||
// find all tags that have `data-scroll as a property`
|
||||
const targets = document.querySelectorAll('[data-scroll-theme]')
|
||||
// are any targets at the top of the window?
|
||||
const isTop = Array.from(targets).map((target) => {
|
||||
const rect = target.getBoundingClientRect();
|
||||
if (rect.y > 1) {
|
||||
return null;
|
||||
}
|
||||
return { target, rect }
|
||||
}).filter(Boolean).sort((a, b) => b.rect.y - a.rect.y)[0]
|
||||
// if we found an element at the top of the document then
|
||||
if (isTop) {
|
||||
|
||||
// set theme color meta tag to the background color of div
|
||||
const color = window.getComputedStyle(isTop.target).getPropertyValue('background-color')
|
||||
if (color) {
|
||||
// find the theme color meta tag and set the attribute to it
|
||||
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', color);
|
||||
}
|
||||
} else if (ogColor) {
|
||||
// set theme color meta tag to original
|
||||
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', ogColor);
|
||||
}
|
||||
// run every 100ms
|
||||
}, 100)
|
||||
|
||||
document.addEventListener('scroll', handleScroll, { passive: true })
|
||||
|
||||
```
|
||||
|
||||
## End result
|
||||
|
||||
The end result is the top bar of safari changes as you scroll between blocks. This has made [Squiggle Squatches](http://squigglesquatches.io/) look way better on mobile.
|
||||
|
||||
<iframe width="662" height="1176" src="https://www.youtube.com/embed/iLksuqZP4L8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
<!--  -->
|
||||
@@ -23,16 +23,16 @@
|
||||
<meta name="twitter:site" content="@@TerribleDev">
|
||||
<meta name="twitter:creator" content="@@TerribleDev">
|
||||
<link rel="canonical" href="@Model.Post.CanonicalUrl" />
|
||||
<link rel="amphtml" href="@Model.Post.AMPUrl">
|
||||
@foreach(var image in Model.Post.Content.Images.Take(6))
|
||||
@if(Model.Post.isAmp)
|
||||
{
|
||||
<meta property="og:image" content="@image">
|
||||
<link rel="amphtml" href="@Model.Post.AMPUrl">
|
||||
}
|
||||
@if(Model.Post.Content.Images.Count > 0)
|
||||
@if(!string.IsNullOrEmpty(Model.Post.ThumbnailImage))
|
||||
{
|
||||
<meta name="twitter:image" content="@(Model.Post.Content.Images[0])">
|
||||
<meta name="twitter:image" content="@(Model.Post.ThumbnailImage)">
|
||||
<meta property="og:image" content="@(Model.Post.ThumbnailImage)" />
|
||||
}
|
||||
<meta property="og:image" content="https://www.gravatar.com/avatar/333e3cea32cd17ff2007d131df336061?s=640" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
@Html.Raw(Model.Post.Content.JsonLDString)
|
||||
</script>
|
||||
|
||||
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 32 KiB |