I followed this tutorial to get a basic map layout set up in React.
After completing it, the "Improve this map" message was constantly outside the map as opposed to the bottom edge: Screenshot
My App.js:
import './App.css';
import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from 'mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
function App() {
mapboxgl.accessToken = 'pk.eyJ1IjoiZmxpZ2h0bWF4IiwiYSI6ImNsZG44enF1bTA2MzIzb3BmZ3FkZHRkcGYifQ.NV8NYyQ01-CLAYGQR_tqBg';
const mapContainer = useRef(null);
const map = useRef(null);
const [lng, setLng] = useState(-6.26);
const [lat, setLat] = useState(53.34);
const [zoom, setZoom] = useState(8);
useEffect(() => {
if (map.current) return; // initialize map only once
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v12',
center: [lng, lat],
zoom: zoom
});
});
useEffect(() => {
if (!map.current) return; // wait for map to initialize
map.current.on('move', () => {
setLng(map.current.getCenter().lng.toFixed(4));
setLat(map.current.getCenter().lat.toFixed(4));
setZoom(map.current.getZoom().toFixed(2));
});
});
return (
<div className="App">
<div className="sidebar">
Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}
</div>
<div ref={mapContainer} className="map-container" />
</div>
);
}
export default App;
index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.map-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 50%;
height: 50%;
}
.sidebar {
background-color: rgba(35, 55, 75, 0.9);
color: #fff;
padding: 6px 12px;
font-family: monospace;
z-index: 1;
position: absolute;
top: 0;
left: 0;
margin: 12px;
border-radius: 4px;
}
Any ideas?
I tried using other tutorials, other styling options, but the message is constantly outside the map.
Silly mistake, forgot to add
import 'mapbox-gl/dist/mapbox-gl.css'
Related
This is going to be part of a module that I want to use in an educational example project, I tried to make Welcome go from left to right and up, every time I press the button, trying to control the movement with commands but it doesn't work.
Requirements:
Only use javascript (forbidden to use jquery or others).
Do not use location.reload () or window.history.go ().
Is there a solution or is it not possible?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#keyframes move {
0% {
top: 250px; left: 0px;
}
50% {
top: 250px; left: 300px;
}
100% {
top: 20px; left: 300px;
}
}
#mh1 {
position: absolute;
animation-name: move;
animation-duration: 3s;
animation-fill-mode: forwards;
}
#keyframes hide {
0% {
opacity: 1;
height: 100%;
line-height: 100%;
padding: 20px;
margin-bottom: 10px;
}
75% {
opacity: 0;
height: 100%;
line-height: 100%;
padding: 20px;
margin-bottom: 10px;
}
100% {
opacity: 0;
height: 0px;
line-height: 0px;
padding: 0px;
margin-bottom: 0px;
}
}
#idesc {
padding: 20px;
margin-bottom: 10px;
animation-name: hide;
animation-duration: 2s;
animation-fill-mode: forwards;
animation-play-state: paused;
}
#keyframes show {
100% {
opacity: 1;
height: 0px;
line-height: 0px;
padding: 0px;
margin-bottom: 0px;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('#but').addEventListener('click', myfunc , false);
function myfunc(event) {
const element2 = document.querySelector('#idesc');
element2.style.animationName = 'show';
const element = document.querySelector('#int');
element.style.animationPlayState = 'initial';
element.innerHTML='<h1 id="mh1">Welcome!</h1>';
setInterval(function(){
const element2 = document.querySelector('#idesc');
element2.style.animationName = 'hide';
element2.style.animationPlayState = 'running';
}, 3000);
element2.style.animationName = "none";
element.style.animationName = "none";
element2.style.animationPlayState = 'initial';
}
});
</script>
</head>
<body>
<div id="idh">
<button id="but">hello
</button>
</div>
<div id="idesc">
<div id="int"></div>
<div id="int2"></div>
</div>
</body>
</html>
I am using react-typescript in my app. For styling I am using style-components. I am creating one Modal alert component. My modal alert is ready and it looks like this, Image. I am checking this sweet alert site. In there they have success icon. I want to use it in my Modal alert component. But I don't know where to find this icon and how to use it in my modal alert component.
This is my modal alert component
import React from 'react';
import iconX from './close.svg';
import styled from 'styled-components';
export const Modals = styled.div`
position: fixed;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
`
const ModalOverlay = styled.div`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .8);
cursor: pointer;
`
const ModalBox = styled.div`
position: relative;
width: 80%;
margin: 0 10%;
padding: 50px;
box-sizing: border-box;
border-radius: 10px;
background-color: white;
cursor: auto;`
const ModalTitle = styled.div`
color: #9E25FC;
font-size: 30px;
text-align: center;
`
const ModalContent = styled.div`
margin-top: 30px;
color: #6B6B6B;
font-size: 16px;`
const ModalClose = styled.button`
position: absolute;
top: 20px;
right: 20px;
transition: transform 250ms ease-in-out;
transform-origin: 50% 50%;
&:hover {
transform: rotate(180deg);
}
`
interface IModalProps {
title: string;
isOpen: boolean;
onClose: () => void;
children?: JSX.Element | string[] | string;
icon?: JSX.Element; //This is icon i am declaring. I am not sure is it JSX.Element.
}
export default ({ title, isOpen, onClose, children }: IModalProps) => {
const outsideRef = React.useRef(null);
const handleCloseOnOverlay = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
if (e.target === outsideRef.current) {
onClose();
}
}
return isOpen ? (
<Modals>
<ModalOverlay
ref={outsideRef}
onClick={handleCloseOnOverlay}
/>
<ModalBox>
<ModalClose
onClick={onClose}
>
<img src={iconX} alt={'close'} />
</ModalClose >
<ModalTitle>
// I want to use it in here the success icon.
{title}
</ModalTitle>
<ModalContent>
{children}
</ModalContent>
</ModalBox>
</Modals>
) : null;
};
I have a list of articles that get filtered by category via a json file. The filters all work, however there is an archive section which has no value in the json file and is outside of the v-for loop. I am looking for a Vue way to add an active class to the archive filter I have created a codepen (Vue filter json feed) where you can see what I am doing.
Array.prototype.unique = function() {
return this.filter(function(value, index, self) {
return self.indexOf(value) === index;
});
}
var vm = new Vue({
el: '#app',
data: {
items: [],
errors: [],
cats: [],
allItems: [],
isActive: false,
catsCount: [],
filteredItems: [],
selectedItem: "Event",
currentPage: 0,
pageSize: 6
},
created() {
axios
.get(`https://codepen.io/struthy/pen/qgXJZJ.js`)
.then(response => {
// JSON responses are automatically parsed.
this.items = response.data;
this.cats = this.items.map(item => item.itemType).unique();
// this.catsCount = this.items.map(item => item.itemType).unique();
})
.catch(e => {
this.errors.push(e);
});
},
computed: {
filteredPage: function() {
var itemSelectedType = this.selectedItem;
if (this.selectedItem === "All") {
return this.items
.sort(function(a, b) {
return new Date(a.published) - new Date(b.published)
})
.slice(0, (this.currentPage * this.pageSize) + this.pageSize)
} else {
return this.items
.sort(function(a, b) {
if (this.selectedItem != "event") {
return new Date(a.published) - new Date(b.published)
}
// else{
// return new Date(a.endDate) - new Date(b.endDate)
// }
})
.filter(function(item) {
return item.itemType === itemSelectedType;
}).slice(0, (this.currentPage * this.pageSize) + this.pageSize);
}
}, // end filteredPage
showMore: function() {
var itemSelectedType = this.selectedItem;
if (this.items.filter(function(item) {
return item.itemType == itemSelectedType
}).length > (this.pageSize * (this.currentPage + 1))) {
return true;
} else if (this.items.length > (this.pageSize * (this.currentPage + 1))) {
return true; // this is all or unfiltered items
}
else {
return false;
}
}, // end showMore
}, // end computed
methods: {
// give an active class to the filter items
activeItem: function(category) {
if (this.selectedItem === category){
return "isActive"
} else {
return ""
}
}, // end activeItem
/// trying to add an active class to the archive link - not succesful yet
activeAllItem: function() {
var allCategory = this.cats
if (this.selectedItem === !allCategory){
return isActive == true
} else {
return isActive == true
}
} // end activeItem
}
});
.grid {
display: flex;
flex-wrap: wrap;
list-style: none;
margin: 0;
padding: 0; }
.grid--space-between {
justify-content: space-between; }
.grid--full {
width: 100%; }
.grid--third {
width: calc(100% / 12 * 4); }
.grid--2third {
width: calc(100% / 12 * 8); }
#media only screen and (max-width: 768px) {
.grid--2third {
width: 100%; } }
.grid__container {
padding-top: 60px;
padding-bottom: 60px;
border-top: 1px solid #e3e3e3;
display: flex;
flex-wrap: wrap; }
.grid__container--padding-left-right {
padding-left: 7.03125%;
padding-right: 7.03125%; }
.grid__container--space-between {
justify-content: space-between; }
.grid__col {
width: 32%;
display: flex;
min-height: 330px;
margin-bottom: 20px; }
#media only screen and (max-width: 1100px) {
.grid__col {
width: 49%; } }
#media only screen and (max-width: 640px) {
.grid__col {
width: 100%; } }
.grid__col--half {
width: 48%; }
.grid__col--half h2 {
padding: 20px 0 0 0; }
#media only screen and (max-width: 768px) {
.grid__col--half {
width: 100%; } }
.grid__col--border {
margin-bottom: 60px;
border-bottom: 4px solid #002A48;
padding-bottom: 60px; }
.grid__col--column {
flex-direction: column; }
.grid__img {
align-self: flex-start; }
.grid__arrow-link {
font-size: 2rem;
font-family: 'Poppins', sans-serif;
font-weight: bold;
position: relative;
width: fit-content; }
.grid__arrow-link:after {
content: " ";
position: absolute;
right: -32px;
top: 10px;
width: 28px;
height: 10px;
background: url(../assets/img/ream-more-blue.png) center no-repeat; }
.grid__box {
background-size: cover;
background-position: center;
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
justify-content: flex-end;
position: relative;
overflow: hidden; }
.grid__box:hover p {
color: #6CB7E3; }
.grid__box--variation {
background-color: #6CB7E3;
color: #fff;
justify-content: space-between; }
.grid__box--variation:hover {
background-color: #57addf; }
.grid__box--variation:hover p {
color: #fff; }
.grid__bg-img {
background-size: cover;
background-position: center -50px;
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
justify-content: flex-end;
transform: scale(1);
-moz-transition: all 0.3s ease-in-out;
-webkit-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out; }
.grid__bg-img:hover {
transform: scale(1.1);
-moz-transition: all 0.3s ease-in-out;
-webkit-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out; }
.grid__head {
padding: 30px 20px 0; }
.grid__head h3 {
color: #fff;
font-size: 3.8rem;
margin-bottom: 20px; }
.grid__caption {
padding: 20px 20px 0;
position: absolute;
bottom: 0;
left: 0;
width: 100%; }
.grid__caption--basic {
background-color: #e3e3e3; }
.grid__caption--variation {
background-color: #6CB7E3; }
.grid__caption h3 {
font-size: 2.8rem;
line-height: 0.7;
padding-bottom: 0;
margin-bottom: 10px;
font-family: 'Poppins', sans-serif; }
.grid__link {
font-size: 2rem;
font-weight: 700;
position: relative;
width: fit-content; }
.grid__link--basic {
color: #6CB7E3; }
.grid__link:after {
content: " ";
position: absolute;
right: -32px;
top: 10px;
width: 28px;
height: 10px;
background: url(../assets/img/ream-more-blue.png) center no-repeat; }
.grid__link--variation {
color: #fff; }
.grid__link--variation:after {
background: url(../assets/img/ream-more-white.png) center no-repeat; }
.grid:after {
content: "";
width: 32%; }
.fullpage-img {
background-size: cover;
background-position: center;
width: 100%;
height: 600px;
display: flex;
justify-content: center;
flex-direction: row;
position: relative; }
.fullpage-img:before {
content: " ";
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
background-color: rgba(0, 42, 72, 0.8); }
.fullpage-img__text {
z-index: 99;
align-self: center;
color: #fff;
width: calc(100% / 12 * 8);
text-align: center; }
.fullpage-img__text h3 {
font-size: 4.4rem;
line-height: 1.363;
font-family: 'Poppins', sans-serif;
font-weight: 700;
color: #fff; }
.fullpage-img__text a {
font-weight: 700;
position: relative;
font-size: 2rem; }
.fullpage-img__text a:after {
content: " ";
position: absolute;
right: -32px;
top: 10px;
width: 28px;
height: 10px;
background: url(../assets/img/ream-more-blue.png) center no-repeat; }
.opportunitiesFilter {
width: calc(100% / 12 * 3);
list-style: none;
margin: 0;
padding: 0;
height: 300px; }
#media only screen and (max-width: 768px) {
.opportunitiesFilter {
width: 100%;
margin-bottom: 30px; } }
.opportunitiesFilter__filter-head {
background: #002A48;
padding: 20px;
font-size: 2.3rem;
font-weight: 700;
color: #fff;
display: block;
margin: 0; }
.opportunitiesFilter__title {
color: #fff;
padding: 20px;
display: inline-block;
font-family: 'Poppins', sans-serif;
font-size: 2.2rem;
font-weight: 700; }
.opportunitiesFilter__list-item {
margin: 0;
padding: 0 20px;
background: #6CB7E3; }
.opportunitiesFilter__list-item--title {
background-color: #002A48; }
.opportunitiesFilter__list-item:last-of-type .opportunitiesFilter__btn {
border: 0; }
.opportunitiesFilter__btn {
background: transparent;
border-radius: 0;
border: 0;
outline: 0;
width: 100%;
margin: 0;
padding: 20px;
text-align: left;
color: #fff;
font-weight: 700;
border-bottom: 1px solid #fff; }
.opportunitiesFilter label {
display: block;
position: relative;
padding: 10px 20px;
cursor: pointer;
background-color: #6CB7E3;
color: #fff;
position: relative; }
.opportunitiesFilter label:before {
content: " ";
display: block;
height: 1px;
width: 85%;
position: absolute;
bottom: 0;
left: 20px;
background-color: #fff; }
.opportunitiesFilter label:last-of-type:before {
display: none; }
.opportunitiesFilter input[type="radio"] {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0; }
.opportunitiesFilter .isActive {
font-weight: bold; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" class="grid__container grid__container--space-between grid__container--padding-left-right">
<div class="opportunitiesFilter">
<h3 class="opportunitiesFilter__filter-head">Filter</h3>
<label v-for="cat in cats">
<input type="radio" v-model="selectedItem" :value="cat" ref="itemRef"/>
<span :class="activeItem(cat)" >{{ cat }}
(
{{ items.filter(function(x){
return x.itemType == cat
}).length }}
) </span>
</label>
<label>
<input type="radio" v-bind:class="{isActive: isActive}" v-model="selectedItem" value="All" />
Archive ({{ items.length }})
</label>
</div>
<ul class="grid grid--2third grid--space-between">
<li class="grid__col grid__col--half grid__col--column grid__col--border" v-for="item in filteredPage">
<img class="grid__img" v-bind:src="item.itemImage">
<!--<h4>{{ item.itemType }} for testing only</h4>-->
<h2>{{ item.title }}</h2>
<p>{{ item.content }}</p>
<a class="grid__arrow-link" :href="item.link">link</a>
</li>
<li v-if="showMore"><button class="btn blue" v-on:click="currentPage++">load more</button></li>
</ul>
</div>
You need to do a couple things, I'd suggest using a computed to create this value, and you need to wrap your value in a span or some other tag to apply the class "isActive". Currently you are adding this class to an input - which will not give you the bold styling you have on the others.
computed: {
isArchiveActive () {
return this.selectedItem === 'All'
}
}
<label>
<input type="radio" v-model="selectedItem" value="All" />
<span v-bind:class="{'isActive': isArchiveActive}">Archive ({{ items.length }})</span
</label>
Here is the forked codepen:
https://codepen.io/anon/pen/Ervdrr?editors=1010
I am using ionic2(3.13) in my application, and I am able to use horizontal tabs perfectly. Is it possible to have vertical tabs, something like below, need help. Thx:
enter image description here
I rewrote some scss to make it work. Hope it helps someone:
ionic version 3.13
tabs.scss (The tabs html file's scss file)
page-tabs {
.tabbar {
top: 0;
width: 5rem;
flex-direction: column;
background-color: #cfa972 !important;
}
ion-header {
left: 5rem;
right: 0;
}
ion-content {
left: 5rem;
right: 0;
}
.tabs-ios .tab-button {
width: 100%;
font-size: 10px;
color: #cfa972;
padding: 0;
&[aria-selected="false"] {
color: #cfa972 !important;
background-color: #cfa972 !important;
}
&[aria-selected="true"] {
color: #ffffff !important;
background-color: #b28850 !important;
}
&[aria-selected="true"] .tab-button-icon {
color: #ffffff;
}
&[aria-selected="false"] .tab-button-icon {
color: #ffffff;
}
}
.has-icon .tab-badge {
right: calc(50% - 22px);
}
.tab-badge {
top: 33%;
}
}
tab root page scss file:
page-mine {
.fixed-content {
left: 0;
right: 0;
top: 0;
bottom: 0;
margin-bottom: 0 !important;
position: absolute;
display: block;
}
.scroll-content {
left: 0;
right: 0;
top: 0;
bottom: 0;
margin-bottom: 0 !important;
position: absolute;
z-index: 1;
display: block;
overflow-x: hidden;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
will-change: scroll-position;
contain: size style layout;
}
}
I am using a pre-made form (Haruki) from https://tympanus.net/Development/TextInputEffects/
JSFiddle is https://jsfiddle.net/kacikw/6b9djm76/#&togetherjs=ERPObvDR7G
I can't figure out how to make the input area into a text area that can have more than 1 line (for a comment section).
Like I don't know how to modify the pre-made form, I tried changing the classes in the html and css to textarea versions of the input (like if it was .input-field I made it .textarea-field)
Please help I'm a desperate student working on my final.
HTML
<div class="cell small-12">
<div class="textarea textarea--haruki">
<div class="textarea__field textarea__field--
haruki" type="text" id="input-3" />
<label class="textarea__label textarea__label--haruki" for="input-3">
<textarea class="textarea__label-content textarea__label-content--haruki">MESSAGE
</textarea>
</label>
</div>
</div>
CSS
.textarea {
position: relative;
z-index: 1;
display: inline-block;
margin: 1em;
max-width: 350px;
width: calc(100% - 2em);
vertical-align: top;
}
.textarea__field {
position: relative;
display: block;
float: right;
padding: 0.8em;
width: 60%;
border: none;
border-radius: 0;
background: #f0f0f0;
color: #aaa;
font-weight: bold;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-appearance: none; /* for box shadows to show on iOS */
}
.textarea__field:focus {
outline: none;
}
.textarea__label {
display: inline-block;
float: right;
width: 40%;
color: #6a7989;
font-weight: bold;
font-size: 70.25%;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.textarea__label-content {
position: relative;
display: block;
padding: .9em 0;
width: 100%;
}
.graphic {
position: absolute;
top: 0;
left: 0;
fill: none;
}
.icon {
color: #ddd;
font-size: 150%;
}
/* Haruki */
.textarea--haruki {
margin: 3em 1em 1em;
}
.textarea__field--haruki {
padding: 1em 0.25em;
width: 100%;
background: transparent;
color: #CC450C;
font-size: 1.55em;
font-family: 'Overpass', sans-serif;
}
.textarea__label--haruki {
position: absolute;
width: 100%;
text-align: left;
pointer-events: none;
}
.textarea__label-content--haruki {
-webkit-transition: -webkit-transform 0.3s;
transition: transform 0.3s;
}
.textarea__label--haruki::before,
.textarea__label--haruki::after {
content: '';
position: absolute;
left: 0;
z-index: -1;
width: 100%;
height: 4px;
background: #BEEFEC;
-webkit-transition:-webkit-transform 0.3s;
transition: transform 0.3s;
}
.textarea__label--haruki::before {
top: 0;
}
.textarea__label--haruki::after {
bottom: 0;
}
.textarea__field--haruki:focus + .textarea__label--haruki
.textarea__label-content--haruki,
.textarea--filled .textarea__label-content--haruki {
-webkit-transform: translate3d(0, -90%, 0);
transform: translate3d(0, -90%, 0);
}
.textarea__field--haruki:focus + .textarea__label--haruki::before,
.textarea--filled .textarea__label--haruki::before {
-webkit-transform: translate3d(0, -0.5em, 0);
transform: translate3d(0, -0.5em, 0);
}
.textarea__field--haruki:focus + .textarea__label--haruki::after,
.textarea--filled .textarea__label--haruki::after {
-webkit-transform: translate3d(0, 0.5em, 0);
transform: translate3d(0, 0.5em, 0);
}
/*for a clear bg*/
[type='text']:focus{
border: none;
background-color: transparent;
box-shadow: none;
}
You don't put input tag into textarea.
Try <textarea cols="10" row="10"></textarea>