Skip to content

Instantly share code, notes, and snippets.

@gnat
Last active September 9, 2023 07:28
Show Gist options
  • Save gnat/c81e3536593c0f43cb57cd25d656cb90 to your computer and use it in GitHub Desktop.
Save gnat/c81e3536593c0f43cb57cd25d656cb90 to your computer and use it in GitHub Desktop.
Inline Stylus CSS demo
<html>
<head>
<title>Inline real time stylus demo</title>
<script>
function stylus_to_css(string){
var cursor=0
// Remove excess indentation (dedent).
var indent=''
while (cursor < string.length) {
if (string[cursor] == "\n") { // Line.
cursor += 1 // Next.
continue
}
if (string[cursor] == "\t" || string[cursor] == " ") {
indent += string[cursor]
cursor += 1 // Next.
continue
}
string = string.replaceAll("\n"+indent, "\n") // Remove.
break
}
// Add curly braces.
var level_from=0
var level_to=0
while (cursor < string.length) {
if (string[cursor] == "\n") { // Line.
level_to = 0
cursor += 1 // Next.
continue
}
if (string[cursor] == "\t") { // Indent.
level_to += 1
cursor += 1 // Next.
continue
}
while (level_to > level_from) { // Real start.
level_from += 1
// Cursor #2 finds last real character for the insert.
var cursor_2 = cursor-1
while (cursor_2 > 0 && ["\n", "\t", " "].includes(string[cursor_2])) {
cursor_2 -= 1
}
cursor_2 += 1
string = string.slice(0, cursor_2) +' {'+ string.slice(cursor_2)
cursor += 2 // Skip ' {'
//cursor += 1 // Next.
continue
}
while (level_from > level_to) { // Real start.
level_from -= 1
// Cursor #2 finds last real character for the insert.
var cursor_2 = cursor-1
while (cursor_2 > 0 && ["\n", "\t", " "].includes(string[cursor_2])) {
cursor_2 -= 1
}
cursor_2 += 1
string = string.slice(0, cursor_2) +'} '+ string.slice(cursor_2)
cursor += 2 // Skip '} '
//cursor += 0 // Next.
continue
}
cursor += 1 // Next.
}
// End of file. Close remaining levels.
while (level_from > 0) {
string += '}'
level_from -= 1
}
function alphanum(c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
}
// Add semicolons.
cursor = 0
while (cursor < string.length) {
if (string[cursor] === "\n") { // Line.
if (cursor > 2) { // Should we add a semicolon?
var c = string[cursor-1]
if (c !== '{' && c !== '}' &&
(c === "\'" || c === '"' || c === ')' || c === '-' || c === '_' || alphanum(c))) {
string = string.slice(0, cursor) +';'+ string.slice(cursor)
}
}
}
cursor += 1 // Next.
}
console.log(string)
return string
}
</script>
<script>
// 🌘 CSS Scope Inline (https://github.com/gnat/css-scope-inline)
window.cssScopeCount ??= 1 // Let extra copies share the scope count.
new MutationObserver((mutations, observer) => {
var cssScopePattern = new RegExp('(\\.me|\\.this|\\.self)(?![A-Za-z0-9\_\-])', 'g') // Can use: .me .this .self
for (var mutation of mutations) {
if (mutation.type !== "childList") continue // Skip if not mutating nodes.
var nodes = [...mutation.addedNodes] // Get new nodes.
for (var node = nodes.shift(); node != null; node = nodes.shift()) { // Process nodes.
nodes.push(...node.childNodes) // Also process children.
if (node.nodeName !== 'STYLE') continue // Skip if not a <style>
if (!node.parentNode || node.parentNode?.nodeName === 'HEAD') continue // Skip if no parent. Don't style <head>
if (node.textContent.includes('.self__')) continue // Skip if already processed.
var scope = 'self__'+(window.cssScopeCount++) // Ready. Make unique scope, example: .self__1234
node.parentNode.classList.add(scope)
node.textContent = stylus_to_css(node.textContent).replace(cssScopePattern, '.'+scope)
}
}
}).observe(document.documentElement, {childList: true, subtree: true})
</script>
</head>
<body>
<h1>Inline real time stylus demo</h1>
<div>
<style>
html
font-family: Noto Sans, sans-serif
h1, h2, h3
font-size: 3rem
margin: 10px
.me
border: none
color: black
font-family: Noto Sans, sans-serif
background: hsl(100 20% 70%)
border: none
border-radius: 12px
box-shadow: 2px 2px 5px #00000044
padding: 10px 20px
color: #222
margin: 20px
animation: bounce 4s ease-in-out infinite
& span
background: hsl(200 50% 70%)
padding: 12px
border-radius: 4px
color: #fff
& ::before
content:'🔮'
padding: 0 4px 0 0
.me
li
list-style: disc
padding: 4px
border-radius: 12px
margin: 4px 20px
@keyframes bounce
0%
transform: translateY(0px)
50%
transform: translateY(20px)
100%
transform: translateY(0px)
</style>
Testing.. testing.. <span>Nested CSS</span>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment