Skip to content

Instantly share code, notes, and snippets.

@stanwmusic
Created February 10, 2022 00:07
Show Gist options
  • Save stanwmusic/00ed5a3c510c88fffa98b8c20c6d6e5b to your computer and use it in GitHub Desktop.
Save stanwmusic/00ed5a3c510c88fffa98b8c20c6d6e5b to your computer and use it in GitHub Desktop.
Native App-Like Mobile Site Concept
.app
.no-int
nav
button(tabindex="0",data-home)
.btn-cnt(tabindex="-1")
svg(class="icon",xmlns="http://www.w3.org/2000/svg",viewBox="0 0 32 32",x="0px",y="0px")
g
polygon(points="16,2 2,12 2,30 30,30 30,12 16,2")
span="Home"
button(tabindex="0",data-menu)
.btn-cnt(tabindex="-1")
svg(class="icon",xmlns="http://www.w3.org/2000/svg",viewBox="0 0 32 32",x="0px",y="0px")
g
line(x1="2",y1="2",x2="30",y2="2")
line(x1="2",y1="16",x2="30",y2="16")
line(x1="2",y1="30",x2="30",y2="30")
span="Menu"
button(tabindex="0",data-target="search")
.btn-cnt(tabindex="-1")
svg(class="icon",xmlns="http://www.w3.org/2000/svg",viewBox="0 0 32 32",x="0px",y="0px")
g
circle(cx="12",cy="12",r="10")
line(x1="20",y1="20",x2="30",y2="30")
span="Search"
.panel(id="menu",data-paneltype="menu")
.menu-items
ul
li
a(href="#")="Sign Up"
li
a(href="#")="Log In"
.panel.active.level1(id="index")
header
.app-name="App Name"
main
button(class="fullwidth",tabindex="0",data-target="panel1")
.btn-cnt(tabindex="-1")="Basic Panel"
button(class="fullwidth",tabindex="0",data-target="panel2")
.btn-cnt(tabindex="-1")="Right-to-Left"
button(class="fullwidth",tabindex="0",data-target="panel3")
.btn-cnt(tabindex="-1")="Panel to More Panels"
button(class="fullwidth",tabindex="0",data-target="slideup")
.btn-cnt(tabindex="-1")="Slide Up"
.panel(id="panel1",data-paneltype="right")
header
button(class="back",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
main
h1="Basic Panel"
p
="Spot something, big eyes, big eyes, crouch, prepare to pounce mrow. Hiss and stare at nothing then run suddenly away instantly break out into full speed gallop across the house for no reason."
p="Hunt by meowing loudly at 5am next to human slave food dispenser sit on the laptop brown cats with pink ears lick sellotape. Burrow under covers refuse to leave cardboard box or steal the warm chair right after you get up. Jump on human and sleep on her all night long be long in the bed, purr in the morning and then give a bite to every human around for not waking up request food, purr loud scratch the walls, the floor, the windows, the humans jumps off balcony then snatches yarn and fights with dog."
.panel(id="panel2",data-paneltype="left")
header
button(class="back",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
main
h1="Right-to-Left"
p="This panel type is ideal for right-to-left languages."
h2="عربى"
p="بقعة شيء، عيون كبيرة، عيون كبيرة، كراوتش، الاستعداد للانقضاض مرو. هيس والتحديق في أي شيء ثم تشغيل فجأة بعيدا كسر الفور إلى فرس بأقصى سرعة عبر المنزل من دون سبب."
h2="עִברִית"
p="ספוט משהו, עיניים גדולות, עיניים גדולות, מתכופפות, מתכונן לזנק. Hiss ולטוש מבט לעבר שום דבר ואז לרוץ פתאום פתאום לפרוץ החוצה במהירות לדהור את הבית ללא סיבה."
.panel(id="panel3",data-paneltype="right")
header
button(class="back",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
main
h1="Panel to More Panels"
button(tabindex="0",data-target="panel3-1")
.btn-cnt(tabindex="-1")="Access Another Panel"
.panel(id="panel3-1",data-paneltype="right")
header
button(class="back",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
main
h1="Another Panel"
button(tabindex="0",data-target="panel3-2")
.btn-cnt(tabindex="-1")="One More"
.panel(id="panel3-2",data-paneltype="right")
header
button(class="back",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
main
h1="Last One"
p="Meow all night having their mate disturbing sleeping humans. Pushes butt to face. Loves cheeseburgers groom yourself 4 hours - checked, have your beauty sleep 18 hours - checked, be fabulous for the rest of the day - checked."
.panel(id="search",data-paneltype="right")
header
button(class="back",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
form(id="form1")
input(type="text",name="search",placeholder="Search…")
button(type="submit",tabindex="0")
.btn-cnt(tabindex="-1")
svg(class="icon",xmlns="http://www.w3.org/2000/svg",viewBox="0 0 32 32",x="0px",y="0px")
g
circle(cx="12",cy="12",r="10")
line(x1="20",y1="20",x2="30",y2="30")
main
.searching
.preloader
="Searching…"
.results
.panel(id="slideup",data-paneltype="up")
header
button(class="close",tabindex="0",data-prev)
.btn-cnt(tabindex="-1")
svg(class="icon",xmlns="http://www.w3.org/2000/svg",viewBox="0 0 32 32",x="0px",y="0px")
g
line(x1="4" y1="4" x2="28" y2="28")
line(x1="28" y1="4" x2="4" y2="28")
main
h1="Slide Up"
p="All sample text about cats in these panels came from "
a(href="http://catipsum.com/",target="_blank")="Cat Ipsum"
="."

Native App-Like Mobile Site Concept

A mobile website layout made to look like a native app whose panels slide in when accessed. It’s not supposed to be a particular kind of app or anything but rather like a template.

The buttons lead to all kinds of panels including one for right-to-left languages, one that leads to more, and one that slides up from the bottom (made to be for displaying announcements, login forms).

The search function works, too but developed only so far. I did add fake loading time just so you can see a fun little preloading animation before results are displayed.

Disclaimer: Any translations to other languages came from Google Translate, so don’t expect them to be 100% accurate.

A Pen by Jon Kantner on CodePen.

License.

console.clear();
$(function(){
var l = 1,
noInt = $(".no-int"),
menuP = $("[data-paneltype=menu]"),
// ensure only elements on current panel can be tabbed
setTabIndexes = function(targetEl, index) {
let els = ["a","button","input"];
for (let el in els) {
$(targetEl + " " + els[el]).attr("tabindex", index);
}
};
setTabIndexes(".app", -1);
setTabIndexes(".level" + l, 0);
setTabIndexes("nav", 0);
// close side with Esc if using keyboard
$(document).on("keydown",function(e){
if (e.keyCode == 27) {
$(".no-int").click();
}
});
noInt.on("click",function(){
$(this).removeClass("no-int-true");
menuP.removeClass("active");
setTabIndexes(".level" + l, 0);
setTabIndexes(".menu-items", -1);
});
// main panel navigation
$("button").on("click",function(){
let dt = $(this).attr("data-target"),
dp = $(this).attr("data-prev"),
dh = $(this).attr("data-home"),
dm = $(this).attr("data-menu");
if (dt) {
let dtId = $("#" + dt);
// prevent breadcrumbing the same panel twice
if (!dtId.hasClass("active")) {
++l;
let prevLvl = $(".level" + (l - 1));
dtId.addClass("active level" + l);
if (dtId.attr("data-paneltype") == "right") {
prevLvl.addClass("prev-left");
} else if (dtId.attr("data-paneltype") == "left") {
prevLvl.addClass("prev-right");
}
}
} else if (dp) {
$(".level" + l).removeClass("active level" + l);
--l;
let prevLvl = $(".level" + l);
if (prevLvl.hasClass("prev-right")) {
prevLvl.removeClass("prev-right");
} else {
prevLvl.removeClass("prev-left");
}
} else if (dh) {
let pnl = $(".panel");
if (pnl.hasClass("prev-left")) {
pnl.removeClass("prev-left");
}
if (pnl.hasClass("prev-right")) {
pnl.removeClass("prev-right");
}
for (let rl = 2; rl <= l; ++rl) {
$(".level" + rl).removeClass("active level" + rl);
}
l = 1;
} else if (dm) {
noInt.toggleClass("no-int-true");
menuP.toggleClass("active");
setTabIndexes(".level" + l, -1);
setTabIndexes(".menu-items", 0);
}
if (!dm) {
if (noInt.hasClass("no-int-true") && menuP.hasClass("active")) {
noInt.removeClass("no-int-true");
menuP.removeClass("active");
}
setTabIndexes(".panel:not(.level" + l + ")", -1);
setTabIndexes(".level" + l, 0);
}
});
// search
$("form").submit(function(){
let sTerm = $(this).find("input[name=search]").val().toLowerCase(),
fakeSTime = Math.floor(Math.random() * (1500 - 500)) + 500;
setTabIndexes(".close", 0);
$(".searching").addClass("s-show");
$(".results").html("");
setTimeout(function(){
let p2search = ["panel1","panel2","panel3"],
rs = [],
rsEl = $(".results");
// get instances of term
for (let p in p2search) {
let pMain = "#" + p2search[p] + " main";
if ($(pMain).html().toLowerCase().indexOf(sTerm) > -1 && sTerm != "") {
rs.push([
$(pMain + " > h1").html(),
$(pMain + " > h1 + p").html() || $(pMain + " > h1 + button .btn-cnt").html()
]);
}
}
$(".searching").removeClass("s-show");
rsEl.addClass("r-show");
// restrict displayed characters for each result
if (rs.length > 0) {
let copyLim = 64,
sTermExp = new RegExp(sTerm,"g");
for (let r in rs) {
if (rs[r][1].length > copyLim) {
rs[r][1] = rs[r][1].substr(0,copyLim);
let lastChar = rs[r][1][rs[r][1].length - 1];
while (lastChar != " ") {
rs[r][1] = rs[r][1].substr(0,rs[r][1].length - 1);
lastChar = rs[r][1][rs[r][1].length - 1];
}
rs[r][1] += "…";
}
// bold the keyword
for (let rp in rs[r]) {
rs[r][rp] = rs[r][rp].replace(sTermExp,"<strong>" + sTerm + "</strong>");
}
let hdg = $("<h3></h3>"),
lnk = $("<a href='#'></a>").html(rs[r][0]),
par = $("<p></p>").html(rs[r][1]);
hdg.append(lnk);
rsEl.append(hdg,par);
}
}
rsEl.prepend($("<p></p>").text(rs.length + " result" + (rs.length != 1 ? "s" : "") + " for \u201C" + sTerm + "\u201D"));
}, fakeSTime);
return false;
});
// prevent scrolling of whole document in mobile devices
$(document).on("touchmove", function(e) {
//e.preventDefault();
});
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
:root {
--color: #406fd2;
font-size: 18px;
}
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body, button, input {
font: 1em "Nunito", sans-serif;
line-height: 1.5;
}
body {
background: #ddd;
color: #333;
}
a {
color: var(--color);
}
.app {
box-shadow: 0 0 5px rgba(0,0,0,0.4);
margin: 15px auto;
overflow: hidden;
position: relative;
height: 568px;
width: 320px;
}
.app-name {
color: #fff;
font-size: 1.5em;
margin: auto;
text-shadow: 0.05em 0.05em 0 rgba(0,0,0,0.5);
}
form {
display: flex;
align-items: center;
height: 3em;
width: 85%;
}
button, input {
border: 0;
border-radius: 0.3em;
}
input {
height: 2em;
margin-right: 0.375em;
padding: 0 0.75em;
width: 100%;
}
main {
height: calc(100% - 3em);
overflow-y: overlay;
padding: 1.5em 0.75em;
}
h1, h2, h3 {
font-family: "Roboto", sans-serif;
}
h1 {
font-size: 2em;
line-height: 1.5;
margin-bottom: 0.75em;
}
h2 {
font-size: 1.5em;
line-height: 1;
margin-bottom: 1em;
}
h3 {
font-size: 1em;
line-height: 1.5;
}
p {
margin-bottom: 1.5em
}
/* Buttons in general and keyboard-only focus */
button {
background: var(--color);
color: #fff;
display: block;
margin-bottom: 0.5em;
overflow: hidden;
transition: all 0.2s;
-webkit-appearance: none;
}
button > .btn-cnt {
padding: 0.5em 0.75em;
}
button[type=submit] {
margin: 0;
}
button[type=submit] > .btn-cnt {
padding: 0.5em;
width: 2em;
height: 2em;
}
button:hover > .btn-cnt {
background: rgba(255,255,255,0.25);
}
button:active > .btn-cnt,
button:focus > .btn-cnt {
background: rgba(0,0,0,0.4);
}
button:focus, .btn-cnt:focus {
outline: 0;
}
.fullwidth {
max-width: 480px;
width: 100%;
}
/* Headers and navigation */
header {
background-color: var(--color);
display: flex;
align-items: center;
justify-content: space-between;
height: 4em;
padding: 1em 0.75em 0 0.75em;
}
header > * {
margin: 0;
}
header + main {
height: calc(100% - 7em);
}
header button {
border-radius: 0;
color: #fff;
}
header button > .btn-cnt {
padding: 0.5em 0;
}
header button,
header button:hover > .btn-cnt,
header button:active > .btn-cnt,
header button:focus > .btn-cnt {
background-color: transparent;
}
header button:hover > .btn-cnt {
opacity: 0.7;
}
header button:active > .btn-cnt,
header button:focus > .btn-cnt {
opacity: 0.4;
}
nav {
background: #444;
bottom: 0;
display: flex;
height: 3em;
z-index: 99;
}
nav button {
background: transparent;
border-radius: 0;
height: 100%;
width: 100%;
}
nav button > .btn-cnt {
padding: 0.5em;
}
nav button > .btn-cnt span {
display: block;
font-size: 0.7em;
margin-top: -0.25em;
}
.menu-items ul {
list-style: none;
}
.menu-items li {
line-height: 3;
}
.menu-items li:nth-of-type(odd) a {
background: rgba(0,0,0,0.4);
}
.menu-items li:nth-of-type(even) a {
background: rgba(0,0,0,0.6);
}
.menu-items li:hover a {
background: rgba(255,255,255,0.25);
}
.menu-items a {
color: #fff;
display: block;
padding: 0 0.75em;
text-decoration: none;
}
.back > .btn-cnt::before {
box-shadow: 3px 3px 0 #fff inset;
content: "";
display: inline-block;
width: 0.75em;
height: 0.75em;
}
.close {
margin: auto 0 auto auto;
}
.close > .btn-cnt {
padding: 0.5em;
}
/* Search */
.preloader,
.preloader::before,
.preloader::after {
border-radius: 50%;
width: 1.5em;
height: 1.5em;
animation-fill-mode: both;
animation: load 1s linear infinite;
}
.preloader {
margin: calc(50% - 1.5em) auto 3em auto;
position: relative;
transform: translateZ(0);
animation-delay: -0.16s;
}
.preloader::before,
.preloader::after {
content: "";
display: block;
position: absolute;
top: 0;
}
.preloader::before {
left: -2.5em;
animation-delay: -0.32s;
}
.preloader::after {
right: -2.5em;
}
.results, .searching {
display: none;
}
.searching {
text-align: center;
}
.r-show, .s-show {
display: inherit;
}
nav, .no-int, .panel {
position: absolute;
width: 100%;
}
.no-int, .panel {
top: 0;
}
/* Panels */
.no-int, .panel {
height: 100%;
}
.no-int {
visibility: hidden;
z-index: 97;
}
.no-int-true {
visibility: visible;
}
.panel {
background-color: #fff;
transition: transform 0.25s ease-out;
z-index: 1;
}
.panel[data-paneltype=right] .back > .btn-cnt {
padding-left: 0.25em;
}
.panel[data-paneltype=right] .back > .btn-cnt::before {
margin-right: 0.25em;
transform: rotate(-45deg);
}
.panel[data-paneltype=left] .back > .btn-cnt {
padding-right: 0.25em;
}
.panel[data-paneltype=left] .back > .btn-cnt::before {
margin-left: 0.25em;
transform: rotate(135deg);
}
.panel[data-paneltype=right] {
transform: translateX(100%);
}
.panel[data-paneltype=left] {
direction: rtl;
transform: translateX(-100%);
}
.panel[data-paneltype=menu],
.panel[data-paneltype=up] {
transform: translateY(100%);
}
.panel[data-paneltype=menu] {
background: #444;
height: auto;
top: auto;
bottom: 3em;
z-index: 98;
}
.panel[data-paneltype=up] {
z-index: 99;
}
.pushed-left {
transform: translateX(-75%);
}
.pushed-right {
transform: translateX(75%);
}
.panel[data-paneltype].active {
transform: translateX(0);
}
.prev-left,
.panel[data-paneltype].prev-left {
transform: translateX(-25%);
}
.prev-right,
.panel[data-paneltype].prev-right {
transform: translateX(25%);
}
/* Icons */
svg > * {
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 4px;
}
.icon {
width: 1em;
height: 1em;
}
.icon > * {
stroke: #fff;
}
.bottom-bar button > .btn-cnt svg {
width: 1.25em;
height: 1.25em;
}
/* Animation */
@keyframes load {
from, to {
box-shadow: 0 2.5em 0 -1em var(--color);
}
50% {
box-shadow: 0 2.5em 0 0 var(--color);
}
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Nunito:400,700" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment