Skip to content

Instantly share code, notes, and snippets.

@grandadmiral-thrawn
Created May 30, 2017 19:22
Show Gist options
  • Save grandadmiral-thrawn/f5a841a2fc68af72492d6fd6f4dfc853 to your computer and use it in GitHub Desktop.
Save grandadmiral-thrawn/f5a841a2fc68af72492d6fd6f4dfc853 to your computer and use it in GitHub Desktop.
Grootbase
<!--
Copyright 2016 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="Demonstrates the use of Google Cloud Database with a Firebase DB">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Grootbase Quickstart</title>
<!-- Disable tap highlight on IE -->
<meta name="msapplication-tap-highlight" content="no">
<!-- Add to homescreen for Chrome on Android -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="Firebase Database Quickstart">
<meta name="theme-color" content="#303F9F">
<!-- Add to homescreen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Firebase Database Quickstart">
<meta name="apple-mobile-web-app-status-bar-style" content="#303F9F">
<!-- Tile icon for Win8 -->
<meta name="msapplication-TileColor" content="#3372DF">
<meta name="msapplication-navbutton-color" content="#303F9F">
<!-- Material Design Lite -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.1.3/material.blue_grey-orange.min.css">
<script defer src="https://code.getmdl.io/1.1.3/material.min.js"></script>
<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-messaging.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyDENbXAaje8RuUiURIHZk44lGgerxhkKg4",
authDomain: "hypergroot.firebaseapp.com",
databaseURL: "https://hypergroot.firebaseio.com",
projectId: "hypergroot",
storageBucket: "hypergroot.appspot.com"
};
firebase.initializeApp(config);
</script>
<!-- *******************************************************************************
* TODO(DEVELOPER): Paste the initialization snippet by navigating to:
https://console.firebase.google.com
and choosing a project you've created. Then click the red HTML logo at the top
right of the page with the caption "Add Firebase to your web app".
Copy the snippet that appears in place of this comment.
*************************************************************************** -->
</head>
<body>
<div class="demo-layout mdl-layout mdl-js-layout mdl-layout--fixed-header">
<!-- Splash screen -->
<section id="page-splash">
<h3 class="logo">Grootbase Web Logger</h3>
<div>
<button id="sign-in-button" class="mdl-button--raised mdl-button mdl-js-button mdl-js-ripple-effect"><i class="material-icons">account_circle</i> Sign in with Google</button>
</div>
</section>
<!-- Header section containing logo and menu -->
<header class="header mdl-layout__header mdl-color-text--white mdl-color--light-blue-700">
<div class="mdl-layout__header-row titlebar">
<h3 class="logo">Grootbase web logger</h3>
</div>
<!-- Navigation Bar -->
<div class="tab mdl-layout__header-row mdl-color--light-blue-600">
<div class="mdl-tab">
<div id="menu-recent" class="mdl-layout__tab is-active mdl-button mdl-js-button mdl-js-ripple-effect">
<i class="material-icons">new_releases</i> Recent
</div>
<div id="menu-my-posts" class="mdl-layout__tab mdl-button mdl-js-button mdl-js-ripple-effect">
<i class="material-icons">home</i>Where I've been
</div>
<div id="menu-my-top-posts" class="mdl-layout__tab mdl-button mdl-js-button mdl-js-ripple-effect">
<i class="material-icons">trending_up</i> Recently occupied
</div>
<button class="mdl-button mdl-js-button mdl-button--fab mdl-color--amber-400 mdl-shadow--4dp mdl-js-ripple-effect" id="add">
<i class="material-icons">mode_edit</i>
</button>
</div>
</div>
</header>
<main class="mdl-layout__content mdl-color--grey-100">
<!-- Show the add post form -->
<section class="mdl-grid content" id="add-post" style="display:none">
<div class="mdl-cell mdl-cell--12-col mdl-grid">
<!-- Card containing the inputs to add a new messages -->
<div class="mdl-card mdl-shadow--2dp mdl-cell mdl-cell--12-col mdl-cell--8-col-tablet
mdl-cell--6-col-desktop">
<div class="mdl-card__title mdl-color--light-blue-600 mdl-color-text--white">
<h2 class="mdl-card__title-text">Where are you?</h2>
</div>
<div class="mdl-card__supporting-text mdl-color-text--grey-600">
<form id="message-form" action="#">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="new-post-title">
<label class="mdl-textfield__label" for="new-post-title">Name of Room...</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<textarea class="mdl-textfield__input" rows="3" id="new-post-message"></textarea>
<label class="mdl-textfield__label" for="new-post-message">What is the event?...</label>
</div>
<button type="submit" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Add To Log
</button>
</form>
</div>
</div>
</div>
</section>
<!-- Show a list of recent posts -->
<section class="mdl-grid content" id="recent-posts-list" style="display:none">
<div class="posts-container mdl-cell mdl-cell--12-col mdl-grid">
</div>
</section>
<!-- Show the list of user's posts -->
<section class="mdl-grid content" id="user-posts-list" style="display:none">
<div class="posts-container mdl-cell mdl-cell--12-col mdl-grid">
</div>
</section>
<!-- Show the list of top user's posts -->
<section class="mdl-grid content" id="top-user-posts-list" style="display:none">
<div class="posts-container mdl-cell mdl-cell--12-col mdl-grid">
</div>
</section>
</main>
</div>
</body>
</html>
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
// Shortcuts to DOM Elements.
var messageForm = document.getElementById('message-form');
var messageInput = document.getElementById('new-post-message');
var titleInput = document.getElementById('new-post-title');
var a = document.querySelectorAll(".md-radio")[0]
var titleInput = document.getElementById('new-post-title');
var signInButton = document.getElementById('sign-in-button');
var splashPage = document.getElementById('page-splash');
var addPost = document.getElementById('add-post');
var addButton = document.getElementById('add');
var recentPostsSection = document.getElementById('recent-posts-list');
var userPostsSection = document.getElementById('user-posts-list');
var topUserPostsSection = document.getElementById('top-user-posts-list');
var recentMenuButton = document.getElementById('menu-recent');
var myPostsMenuButton = document.getElementById('menu-my-posts');
var myTopPostsMenuButton = document.getElementById('menu-my-top-posts');
/**
* Saves a new post to the Firebase DB.
*/
// [START write_fan_out]
function writeNewPost(uid, username, title, body) {
// A post entry.
var postData = {
author: username,
uid: uid,
body: body,
title: title,
starCount: 0,
};
// Get a key for a new Post.
var newPostKey = firebase.database().ref().child('posts').push().key;
// Write the new post's data simultaneously in the posts list and the user's post list.
var updates = {};
updates['/posts/' + newPostKey] = postData;
updates['/user-posts/' + uid + '/' + newPostKey] = postData;
return firebase.database().ref().update(updates);
}
// [END write_fan_out]
/**
* Star/unstar post.
*/
// [START post_stars_transaction]
function toggleStar(postRef, uid) {
postRef.transaction(function(post) {
if (post.stars && post.stars[uid]) {
post.starCount--;
post.stars[uid] = null;
} else {
post.starCount++;
if (!post.stars) {
post.stars = {};
}
post.stars[uid] = true;
}
return post;
});
}
// [END post_stars_transaction]
/**
* Creates a post element.
*/
function createPostElement(postId, title, text, author) {
var uid = firebase.auth().currentUser.uid;
var html =
'<div class="post mdl-cell mdl-cell--12-col ' +
'mdl-cell--6-col-tablet mdl-cell--4-col-desktop mdl-grid mdl-grid--no-spacing">' +
'<div class="mdl-card mdl-shadow--2dp">' +
'<div class="mdl-card__title mdl-color--light-blue-600 mdl-color-text--white">' +
'<h4 class="mdl-card__title-text"></h4>' +
'</div>' +
'<div class="header">' +
'<div>' +
'<div class="avatar"></div>' +
'<div class="username mdl-color-text--black"></div>' +
'</div>' +
'</div>' +
'<span class="star">' +
'<div class="not-starred material-icons">star_border</div>' +
'<div class="starred material-icons">star</div>' +
'<div class="star-count">0</div>' +
'</span>' +
'<div class="text"></div>' +
'<div class="comments-container"></div>' +
'<form class="add-comment" action="#">' +
'<div class="mdl-textfield mdl-js-textfield">' +
'<input class="mdl-textfield__input new-comment" type="text">' +
'<label class="mdl-textfield__label">Comment...</label>' +
'</div>' +
'</form>' +
'</div>' +
'</div>';
// Create the DOM element from the HTML.
var div = document.createElement('div');
div.innerHTML = html;
var postElement = div.firstChild;
componentHandler.upgradeElements(postElement.getElementsByClassName('mdl-textfield')[0]);
var addCommentForm = postElement.getElementsByClassName('add-comment')[0];
var commentInput = postElement.getElementsByClassName('new-comment')[0];
var star = postElement.getElementsByClassName('starred')[0];
var unStar = postElement.getElementsByClassName('not-starred')[0];
// Set values.
postElement.getElementsByClassName('text')[0].innerText = text;
postElement.getElementsByClassName('mdl-card__title-text')[0].innerText = title;
postElement.getElementsByClassName('username')[0].innerText = author;
// Listen for comments.
// [START child_event_listener_recycler]
var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', function(data) {
addCommentElement(postElement, data.key, data.val().text, data.val().author);
});
commentsRef.on('child_changed', function(data) {
setCommentValues(postElement, data.key, data.val().text, data.val().author);
});
commentsRef.on('child_removed', function(data) {
deleteComment(postElement, data.key);
});
// [END child_event_listener_recycler]
// Listen for likes counts.
// [START post_value_event_listener]
firebase.database().ref('posts/' + postId + '/starCount').on('value', function(snapshot) {
updateStarCount(postElement, snapshot.val());
});
// [END post_value_event_listener]
// Listen for the starred status.
firebase.database().ref('posts/' + postId + '/stars/' + uid).on('value', function(snapshot) {
updateStarredByCurrentUser(postElement, snapshot.val());
});
// Create new comment.
addCommentForm.onsubmit = function(e) {
e.preventDefault();
createNewComment(postId, firebase.auth().currentUser.displayName, uid, commentInput.value);
commentInput.value = '';
commentInput.parentElement.MaterialTextfield.boundUpdateClassesHandler();
};
// Bind starring action.
var onStarClicked = function() {
var globalPostRef = firebase.database().ref('/posts/' + postId);
var userPostRef = firebase.database().ref('/user-posts/' + uid + '/' + postId);
toggleStar(globalPostRef, uid);
toggleStar(userPostRef, uid);
};
unStar.onclick = onStarClicked;
star.onclick = onStarClicked;
return postElement;
}
/**
* Writes a new comment for the given post.
*/
function createNewComment(postId, username, uid, text) {
firebase.database().ref('post-comments/' + postId).push({
text: text,
author: username,
uid: uid
});
}
/**
* Updates the starred status of the post.
*/
function updateStarredByCurrentUser(postElement, starred) {
if (starred) {
postElement.getElementsByClassName('starred')[0].style.display = 'inline-block';
postElement.getElementsByClassName('not-starred')[0].style.display = 'none';
} else {
postElement.getElementsByClassName('starred')[0].style.display = 'none';
postElement.getElementsByClassName('not-starred')[0].style.display = 'inline-block';
}
}
/**
* Updates the number of stars displayed for a post.
*/
function updateStarCount(postElement, nbStart) {
postElement.getElementsByClassName('star-count')[0].innerText = nbStart;
}
/**
* Creates a comment element and adds it to the given postElement.
*/
function addCommentElement(postElement, id, text, author) {
var comment = document.createElement('div');
comment.classList.add('comment-' + id);
comment.innerHTML = '<span class="username"></span><span class="comment"></span>';
comment.getElementsByClassName('comment')[0].innerText = text;
comment.getElementsByClassName('username')[0].innerText = author;
var commentsContainer = postElement.getElementsByClassName('comments-container')[0];
commentsContainer.appendChild(comment);
}
/**
* Sets the comment's values in the given postElement.
*/
function setCommentValues(postElement, id, text, author) {
var comment = postElement.getElementsByClassName('comment-' + id)[0];
comment.getElementsByClassName('comment')[0].innerText = text;
comment.getElementsByClassName('fp-username')[0].innerText = author;
}
/**
* Deletes the comment of the given ID in the given postElement.
*/
function deleteComment(postElement, id) {
var comment = postElement.getElementsByClassName('comment-' + id)[0];
comment.parentElement.removeChild(comment);
}
/**
* Starts listening for new posts and populates posts lists.
*/
function startDatabaseQueries() {
// [START my_top_posts_query]
var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().ref('user-posts/' + myUserId).orderByChild('starCount');
// [END my_top_posts_query]
// [START recent_posts_query]
var recentPostsRef = firebase.database().ref('posts').limitToLast(100);
// [END recent_posts_query]
var userPostsRef = firebase.database().ref('user-posts/' + myUserId);
var fetchPosts = function(postsRef, sectionElement) {
postsRef.on('child_added', function(data) {
var containerElement = sectionElement.getElementsByClassName('posts-container')[0];
containerElement.insertBefore(
createPostElement(data.key, data.val().title, data.val().body, data.val().author),
containerElement.firstChild);
});
};
fetchPosts(topUserPostsRef, topUserPostsSection);
fetchPosts(recentPostsRef, recentPostsSection);
fetchPosts(userPostsRef, userPostsSection);
}
/**
* Writes the user's data to the database.
*/
// [START basic_write]
function writeUserData(userId, name, email) {
firebase.database().ref('users/' + userId).set({
username: name,
email: email
});
}
// [END basic_write]
// Bindings on load.
window.addEventListener('load', function() {
// Bind Sign in button.
signInButton.addEventListener('click', function() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider);
});
// Listen for auth state changes
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
splashPage.style.display = 'none';
writeUserData(user.uid, user.displayName, user.email);
startDatabaseQueries();
} else {
splashPage.style.display = 'block';
}
});
// Saves message on form submit.
messageForm.onsubmit = function(e) {
e.preventDefault();
if (messageInput.value && titleInput.value) {
var postText = messageInput.value;
messageInput.value = '';
// [START single_value_read]
var userId = firebase.auth().currentUser.uid;
firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) {
var username = snapshot.val().username;
// [START_EXCLUDE]
writeNewPost(firebase.auth().currentUser.uid, firebase.auth().currentUser.displayName,
titleInput.value, postText).then(function() {
myPostsMenuButton.click();
});
// [END_EXCLUDE]
});
// [END single_value_read]
}
};
// Bind menu buttons.
recentMenuButton.onclick = function() {
recentPostsSection.style.display = 'block';
userPostsSection.style.display = 'none';
topUserPostsSection.style.display = 'none';
addPost.style.display = 'none';
recentMenuButton.classList.add('is-active');
myPostsMenuButton.classList.remove('is-active');
myTopPostsMenuButton.classList.remove('is-active');
};
myPostsMenuButton.onclick = function() {
recentPostsSection.style.display = 'none';
userPostsSection.style.display = 'block';
topUserPostsSection.style.display = 'none';
addPost.style.display = 'none';
recentMenuButton.classList.remove('is-active');
myPostsMenuButton.classList.add('is-active');
myTopPostsMenuButton.classList.remove('is-active');
};
myTopPostsMenuButton.onclick = function() {
recentPostsSection.style.display = 'none';
userPostsSection.style.display = 'none';
topUserPostsSection.style.display = 'block';
addPost.style.display = 'none';
recentMenuButton.classList.remove('is-active');
myPostsMenuButton.classList.remove('is-active');
myTopPostsMenuButton.classList.add('is-active');
};
addButton.onclick = function() {
recentPostsSection.style.display = 'none';
userPostsSection.style.display = 'none';
topUserPostsSection.style.display = 'none';
addPost.style.display = 'block';
recentMenuButton.classList.remove('is-active');
myPostsMenuButton.classList.remove('is-active');
myTopPostsMenuButton.classList.remove('is-active');
messageInput.value = '';
titleInput.value = '';
};
recentMenuButton.onclick();
}, false);
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
html, body {
font-family: 'Roboto', 'Helvetica', sans-serif;
}
a {
text-decoration: underline;
color: #039BE5;
}
.mdl-menu a {
text-decoration: none;
}
.content {
max-width: 1024px;
}
.mdl-card {
display: block;
}
h3 {
background: url('firebase-logo.png') no-repeat;
background-size: 40px;
padding-left: 50px;
background-position-y: -2px;
}
.mdl-textfield {
width: 100%;
}
/* Fixes an MDL bug where the header does not scroll on small devices */
.mdl-layout__container .mdl-layout--fixed-header .mdl-layout__content {
overflow-y: visible;
overflow-x: visible;
overflow: visible;
}
/* Overrides MDL colors */
.mdl-layout.is-upgraded .mdl-layout__tab.is-active::after,
.header .mdl-textfield__label:after {
background-color: #FFCA28;
}
.mdl-snackbar__action {
color: #FFCA28;
}
.mdl-textfield__label:after {
background-color: #0288D1;
}
.mdl-textfield--floating-label.is-focused .mdl-textfield__label {
color: #0288D1;
}
/* Header */
.logo {
font-family: 'Amaranth', sans-serif;
}
.logo .material-icons {
top: 4px;
font-size: 32px;
margin-right: -2px;
position: relative;
}
.header .mdl-layout__header-row {
max-width: 1024px;
width: 100%;
height: auto;
padding: 10px 20px;
margin: auto;
position: relative;
}
@media screen and (max-width: 840px) {
.header .mdl-layout__header-row.titlebar {
height: 56px;
}
.titlebar h3 {
font-size: 24px;
}
.titlebar h3 .material-icons {
top: 2.5px;
font-size: 23px;
}
}
@media screen and (max-width: 479px) {
.mdl-grid {
padding: 0;
}
.mdl-card {
font-size: 14px;
}
}
/* Signed-in user */
.avatar {
height: 32px;
width: 32px;
display: inline-block;
background-size: 32px 32px;
border-radius: 32px;
border: 2px white solid;
margin-right: 10px;
background-image: url('./silhouette.jpg');
}
.username {
display: inline-block;
line-height: 38px;
vertical-align: top;
width: calc(100% - 46px);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
#sign-in-button {
margin-left: 10px;
color: inherit;
}
.mdl-button .material-icons {
margin-top: -2px;
}
.mdl-button.mdl-button--icon .material-icons,
.mdl-button.mdl-button--fab .material-icons {
margin-top: 0;
}
/* Navigation Bar */
.header .mdl-tab {
padding-left: 23px;
box-sizing: border-box;
width: 100%;
height: 100%;
overflow: visible;
position: relative;
margin: auto;
max-width: 1024px;
}
@media screen and (max-width: 609px) {
.header .mdl-tab {
width: auto;
}
}
.header .tab {
padding: 0;
max-width: none;
}
#add {
position: absolute;
right: 20px;
top: 18px;
z-index: 998;
}
@media screen and (max-width: 840px) {
#add {
position: fixed;
bottom: 10px;
right: 10px;
z-index: 998;
top: auto;
}
}
/* Drawer */
.mdl-layout__drawer-button {
display: none;
}
.mdl-layout__drawer .mdl-navigation .mdl-navigation__link.is-active,
.is-active .mdl-menu__item {
color: black;
background-color: #EBEBEB;
}
.mdl-layout__drawer {
border-right-width: 0;
}
.mdl-navigation__link .material-icons, .mdl-menu__item .material-icons {
position: relative;
margin-top: -2px;
margin-right: 10px;
}
.mdl-menu__item .material-icons {
top: 7px;
}
@media screen and (max-width: 479px) {
.mdl-layout__drawer-button {
display: block;
top: 3px;
}
}
/* New Post Page */
#page-add {
display: block;
text-align: center;
}
#page-add .mdl-cell {
width: auto;
min-width: 300px;
}
#newPictureContainer {
margin: 0;
max-width: 100%;
max-height: 400px;
}
@media screen and (max-width: 479px) {
.mdl-snackbar__action {
margin-right: 60px;
}
}
.comments-container .username {
width: auto;
}
.comments-container .comment{
display: inline-block;
vertical-align: top;
padding-left: 10px;
color: grey;
line-height: 25px;
}
.comments-container .username {
line-height: 25px;
}
/* Post */
.post .mdl-card {
height: 100%;
top: 0;
left: 0;
min-height: 0;
}
.post .header {
padding: 10px;
width: calc(100% - 100px);
display: inline-block;
}
.post .star-count {
color: #444;
padding: 0 10px 0 5px;
font-weight: bold;
display: inline-block;
top: -10px;
position: relative;
}
.post .comments-container {
padding: 15px 10px 0 10px;
}
.post .text {
padding: 0 10px;
color: grey;
}
.post .comments-container .text {
margin-left: 5px;
color: #444;
transition: all 0.2s;
}
.post .add-comment{
flex-grow: 1;
padding: 0 10px;
margin-bottom: -10px;
}
.post .add-comment.mdl-textfield {
width: 100%;
}
.post .star {
position: absolute;
top: 10px;
right: 0;
}
.post .star .material-icons {
font-size: 35px;
color: #ffcb0c;
cursor: pointer;
}
.post .star .material-icons:HOVER {
opacity: 0.6;
}
.post .star .starred {
display: none;
}
/* Splash Page */
#page-splash {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #0288D1;
background: radial-gradient(circle, #039BE5, #01579b);
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
color: white;
flex-direction: column;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment