How to stack cards for Solitaire? - javascript

Trying to do this project on my own running into some slight issues. I have decided to cut the card with overflow so that I can stack but the stack isn't exactly working. The goal is to get the cards to stack together more. I have attached a picture along with code for the css portion and code for the react portion, I pretty much use that same code in a component and call that component seven times to get all 7 columns. I have the functionality that loads the cards into the game. I have also included details concerning the steps I have tried from other articles that were similar to my question.
Here is my css code :
body {
background: #339900;
}
.container {
width: 1700px;
border: 1px solid blue;
}
span {
display: block;
}
.outline {
text-align: center;
background: #FFF;
color: #cc0033;
border: 1px solid black;
}
.scene {
width: 120px;
height: 180px;
perspective: 360px;
}
.top{
text-align: left;
}
.bottom{
text-align: right;
}
.topRow{
display: flex;
}
.drawPile {
display: flex;
margin-right: 300px;
width: 500px;
}
.finalStack {
width: 900px;
display: flex;
justify-content: space-between;
}
.bottomRow {
display: flex;
justify-content: space-between;
margin-top: 100px;
}
.drawFrom {
display: flex;
justify-content: center;
text-align: center;
align-content: center;
background: blue;
}
.black {
color: black;
}
.red {
color: red;
}
.deck {
display: flex;
height: 200px;
flex-direction: column;
}
.card {
flex: 100px 1 0;
border: solid 1px black;
border-radius: 5px;
background-color: white;
box-shadow: 3px 3px 3px gray;
width: 120px;
height: 180px;
}
.stackedCards {
max-height: 50px;
overflow: hidden;
}
.lastInStack {
overflow: auto;
}
Not sure if this is needed but I will post the code for each section. I am doing this in react.
render() {
console.log("BottomSection");
console.log(this.props);
const cards = this.props.cards;
console.log(cards);
return (
<div>
{cards.map((card, id) => (
<div key = {id} className="deck">
<div onClick = {this.clickingCard} draggable = "true" className = { id === this.props.cards.length -1 ? "card lastInStack outline scene column" : "card stackedCards outline scene column"}>
<div className={"top " + card.color}>
<span>{card.value}</span>{" "}
{card.suit === "hearts" ? (
<span>♥</span>
) : card.suit === "spades" ? (
<span>♠</span>
) : card.suit === "clubs" ? (
<span>♣</span>
) : (
<span>♦</span>
)}
</div>
{card.suit === "hearts" ? (
<h1 className={card.color}>♥</h1>
) : card.suit === "spades" ? (
<h1 className={card.color}>♠</h1>
) : card.suit === "clubs" ? (
<h1 className={card.color}>♣</h1>
) : (
<h1 className={card.color}>♦</h1>
)}
<div className={"bottom " + card.color}>
{card.suit === "hearts" ? (
<span>♥</span>
) : card.suit === "spades" ? (
<span>♠</span>
) : card.suit === "clubs" ? (
<span>♣</span>
) : (
<span>♦</span>
)}
<span>{card.value}</span>
{/* <hr/> */}
</div>
</div>
</div>
))}
</div>
);
}
Okay, so the idea here is to stack the cards up so that they are connected with no green space between the cards. I will have to turn the cards over or have a back side but right now I am just trying to stack the cards. I will worry about the backside and clicking a card to reveal its other side once I actually get everything to stack up correctly. I have tried to use margin-bottom at a negative amount however this seems to only stretch the card itself and make it longer. Not sure if this is because of the way I am creating each individual card instead of using images. I also tried using negative top and position relative as one of the articles recommended but didn't see a change. The other articles didn't seem to apply to my implementation.

.deck {
display: flex;
flex-direction: column;
}
.lastInstack {
/*leave blank no need for overflow*/
}
This is the solution to the way I implemented the code. The changes were looked into by Peter Ambruzs as well. The reason why it was not working is that of the height set on deck it separated each div by the height. Removing the height removes the separation.

Related

How To Animate Buttons In A Speed Dial

I am building my own SpeedDial which is inspired by the Material UI one, but can't currently figure out how I can make the hidden buttons transition smoothly like they do in the example link above when the SpeedDial is hovered. It's not like they are sliding out, but each button appears one after the other smoothly. If you go to the link above, you will see what I mean. Select the "left" direction, since it is most like my example code.
Here is a quick screenshot of what the SpeedDial looks like, just in case you are wondering.
I have a working CodeSandbox where I have the entire Speed Dial built, but it's lacking the animation I am looking for. My initial thought was to not conditionally render the components, and have them always visible, but use visibility: hidden. However, I don't think doing that solves my problem, and won't allow for any transitions to be set.
For sake of completeness, I will include all of the code, but I highly recommend that you just mess around with the CodeSandbox, as it already works.
App.js
import { useState } from "react";
import SpeedDial from "./components/SpeedDial";
import SpeedDialAction from "./components/SpeedDialAction";
import "./styles.css";
const actions = [
{ label: "share", icon: "share " },
{ label: "print", icon: "print" },
{ label: "save", icon: "floppy-o" },
{ label: "copy", icon: "copy" }
];
export default function App() {
const [activeAction, setActiveAction] = useState("");
return (
<div className="App">
<SpeedDial
direction="left"
style={{
position: "absolute",
bottom: 40,
right: 40
}}
>
{actions.map((action) => (
<SpeedDialAction
key={action.label}
direction="left"
setActiveAction={setActiveAction}
hovered={action.label === activeAction}
label={action.label}
icon={action.icon}
/>
))}
</SpeedDial>
</div>
);
}
Basically, the SpeedDial component accepts children, specifically an array that will create several SpeedDialAction components. When the SpeedDial button is hovered, the SpeedDialAction components become visible next to the main SpeedDial button (the blue button). When the mouse is moved out of the SpeedDial, they disappear.
SpeedDial.js
import React, { useState } from "react";
import Icon from "./Icon";
import "./SpeedDial.css";
export default function SpeedDial({ children, direction, style }) {
const [hovered, setHovered] = useState(false);
return (
<div
className={`speed-dial ${direction}`}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => {
setHovered(false);
}}
onClick={() => {
setHovered(!hovered);
}}
style={style}
>
<button className="main-btn">
<Icon
name="plus"
style={{
transform: hovered ? "rotate(45deg" : "none",
transition: "transform ease .25s"
}}
/>
</button>
<div className={`action-wrapper ${direction}`}>{hovered && children}</div>
</div>
);
}
SpeedDial.defaultProps = {
direction: "right",
onClick: () => {}
};
Notice how in the action-wrapper that this is where we are conditionally rendering the SpeedDialAction components via the children prop. I am aware that conditionally rendering like this works pretty much like display: none, and won't allow me to animate it. That's why I hope you can help!
SpeedDial.css
.speed-dial {
display: inline-flex;
position: relative;
align-items: center;
width: auto;
}
.speed-dial.top {
flex-direction: column-reverse;
align-items: flex-start;
justify-content: center;
}
.speed-dial.bottom {
flex-direction: column;
align-items: flex-start;
justify-content: center;
}
.speed-dial.left {
flex-direction: row-reverse;
}
.speed-dial > .main-btn {
background: rgb(25, 118, 210);
height: 60px;
width: 60px;
border-radius: 50%;
color: white;
font-size: 18px;
cursor: pointer;
box-shadow: rgb(0 0 0 / 20%) 0px 3px 5px -1px,
rgb(0 0 0 / 14%) 0px 6px 10px 0px, rgb(0 0 0 / 12%) 0px 1px 18px 0px;
}
.speed-dial > .action-wrapper {
display: flex;
}
.speed-dial > .action-wrapper.top {
flex-direction: column;
align-items: flex-start;
transform: translateX(7px);
}
.speed-dial > .action-wrapper.bottom {
flex-direction: column;
align-items: flex-start;
transform: translateX(7px);
}
SpeedDialAction.js
import React from "react";
import Icon from "./Icon";
import "./SpeedDialAction.css";
export default function SpeedDialAction({
icon,
label,
hovered,
setActiveAction,
direction,
onClick
}) {
return (
<div className="speed-dial-action" onClick={onClick}>
{hovered && <div className={`label ${direction}`}>{label}</div>}
<button
onMouseEnter={() => setActiveAction(label)}
onMouseLeave={() => setActiveAction("")}
className={direction}
>
<Icon name={icon} />
</button>
</div>
);
}
Nothing crazy going on here, I just added it for sake of thoroughness.
SpeedDialAction.css
.speed-dial-action {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.speed-dial-action button {
box-shadow: rgb(0 0 0 / 20%) 0px 3px 5px -1px,
rgb(0 0 0 / 14%) 0px 6px 10px 0px, rgb(0 0 0 / 12%) 0px 1px 18px 0px;
background: white;
height: 45px;
width: 45px;
border-radius: 50%;
font-size: 20px;
cursor: pointer;
}
.speed-dial-action button:hover {
background: #d8d8d8;
}
.speed-dial-action button.left {
margin-right: 15px;
}
.speed-dial-action button.right {
margin-left: 15px;
}
.speed-dial-action button.bottom {
margin-top: 15px;
}
.speed-dial-action button.top {
margin-bottom: 15px;
}
.speed-dial-action .label {
background: #565656;
color: white;
padding: 5px 8px;
position: absolute;
border-radius: 4px;
text-transform: capitalize;
}
.speed-dial-action .label.left {
top: -40px;
}
.speed-dial-action .label.right {
top: -40px;
}

What changed in bootstrap 5 to make controls assume max size

I recently upgraded NodeJs to 16.13.0 from 14.x. One of the modules updated was bootstrap of course. I also had to get rid of my Jumbotron control because of the upgrade, but I don't think that's part of the issue I am having. I have quite a few <div> controls with the className marked as 'row'. However, after the upgrade, 'row' is being ignored and all other controls are on separate lines with max width set to container width.
For example, in the image you can see my Totals control shows Subtotal with the subtotal value on the next line. My Totals component:
import React from 'react';
import { GetTotal } from './CartHandler';
import { formatter } from '../common.js'
import "./Checkout.scss"
export default function TotalsBlock(props) {
let carttotal = GetTotal();
let shipping = 10.57;
let taxes = 4.93;
return (
<aside id="checkout" className="block col-1">
<h1>Total</h1>
<div className="row">
<label>Subtotal</label>
<label>{formatter.format(carttotal)}</label>
</div>
<div className="row">
<label>Shipping</label>
<label>{formatter.format(shipping)}</label>
</div>
<div className="row">
<label>Taxes</label>
<label>{formatter.format(taxes)}</label>
</div>
<hr/>
<div className="row">
<label>Total</label>
<label>{formatter.format(carttotal + shipping + taxes)}</label>
</div>
</aside>
);
}
... and Checkout.scss:
#checkout {
.row {
display: flex;
align-items: stretch;
justify-content: space-between;
margin-right: 0;
margin-left: 0;
font-size: 12px;
}
h1 {
font-size: 1rem;
font-weight: bold;
}
.col-1 {
flex: 1;
max-width: 33%;
}
.col-2 {
flex: 2;
max-width: 66%;
}
.header {
background-color: cornflowerblue;
color: white;
}
.block {
background-color: lightgray;
padding: 1rem;
margin: 0.5rem;
border-radius: 0.5rem;
}
.table-wrapper {
max-height: 200px;
overflow: auto;
}
th.price, th.quantity {
width: 10%;
}
.table-extra {
}
}
What changed in bootstrap 5 to not make 'row' work and why are my elements max size? I think these are both the same actual problem. Any help will be appreciated.
UPDATE
When I inspect with the Browser's DevTools .row width is set to 100%. I can uncheck it or set width to auto everything goes back to normal. However, I put width: auto in .row in the Checkout.scss it gets set to 100% anyway...
Not the best way I suppose...
I added:
.row > * {
width: auto;
}
...to Checkout.scss to overwrite bootstrap. I am all ears if anyone has a better Solution.

Style adjustments in a reactJS dropdown Menu

I'm currently building a ReactJS App, and I needed to implement a dropdown menu.
I currently have the menu built, but I need help for two elements :
The style of the menu
The position of the menu
1 - Style of the menu
The menu looks like that :
But when I hoover the menu, there is a gap between the hovering of a link and the link itselfs.
For example :
Here I hoover 'Rename', but styling come under it...
2 - Position of the menu
Simple question : How can I choose myself the position of the menu in my page ?
Neither relative to the parent element nor in a fixed page position ?
Here are my source codes :
VerticalDots.js
import React from "react";
import "./VerticalDots.css";
export default class VerticalDots extends React.Component {
state = {
status: false,
elements: [
"Rename",
"Duplicate",
"Archive",
"Delete Permanently"
]
}
buttonClick = (e, curstat) => {
e.stopPropagation();
this.setState({ status: curstat });
};
displayElements(){
if(this.state.status){
return(
<div className="show-options">
{this.state.elements.map((value, key) => {
return (
<div className="data-row">{value}</div>
);
})}
</div>
);
}
}
render() {
return (
<div className="dropdown-root">
<div className="text-box">
<div className="button" onClick={e => this.buttonClick(e, !this.state.status)}>
<img src={require("../imgs/3dots-vertical.png")} alt="NotFound"/>
</div>
{this.displayElements()}
</div>
</div>
);
}
}
VerticalDots.css
.text-box {
width: 100px;
height: 40px;
position: relative;
text-align: left;
}
.button {
text-align: right;
font-size: 13px;
}
.show-options {
height: 110px;
width: 150px;
border: 1px solid #7A7A7A;
border-radius: 4px;
position: relative;
background: #EBEBEB;
cursor: pointer;
overflow-y: scroll;
overflow-x: hidden;
z-index: 1;
}
.data-row {
height: 20px;
text-align: left;
/* margin: 0px 10px 0px 10px; */
color: #25073C;
border-radius: 4px;
}
.data-row:hover {
background-color: #1464F6;
color: white;
}
.drop-text {
margin-top: 10px;
margin-left: 5px;
position: absolute;
}
.column9:hover{
background-color: red;
}
https://codesandbox.io/s/cool-engelbart-tuz4y
I couldn't recreate your first issue, can you please clarify further on what's happening on your end? It might be that you have other styles included that are causing that issue.
Regarding issue number 2, normal css rules apply to .show-options which is a child of .text-box. I am not sure how you want to position it, but one suggestion would be to use flex, something like:
.text-box {
height: auto;
display: flex;
flex-direction: column
}
I solved the problem, a hidden line-height was linked 3 branches above.
Thank you for your time !

Is flexbox snapping to grid with text wrapping possible?

So I like this, where it wraps but yet the boxes all align on both sides and fill the whole space.
<head>
<style>
* {
padding: 0px;
margin: 0px;
text-transform: none;
font-style: normal;
}
p {
display: flex;
flex-wrap: wrap;
width: 200px;
}
i {
flex: 1;
padding: 5px;
margin: 2px;
background: #ddd;
text-align: center;
}
</style>
</head>
<body>
<p>
<i>foo</i><i>hello</i><i>congratulations</i><i>forward</i><i>interesting</i><i>place</i><i>walk</i><i>to</i><i>anyplace</i><i>next</i><i>sophisticationism</i>
</p>
</body>
Using a mix of small and large words, it somehow figures out how to optimally lay them out so it fills the space completely.
What I would like to do now is, instead of having each box be a dynamically width'd rectangle, I would like for the boxes to "snap to a grid" so to speak. That is, imagine there was a grid of squares that stretched across each row. Sort of like this (which I've completely hardcoded, just for the sake of demonstrating what it looks like. In reality this is what my question is about, how to make this automatic using FlexBox).
<head>
<style>
* {
padding: 0px;
margin: 0px;
text-transform: none;
font-style: normal;
}
p {
display: flex;
flex-wrap: wrap;
width: 220px;
}
i {
width: 50px;
height: 50px;
padding: 5px;
margin: 2px;
background: #ddd;
text-align: center;
}
.l {
width: 114px;
}
</style>
</head>
<body>
<p>
<i>a</i><i>a</i><i>a</i><i>a</i><i class='l'>long</i><i>a</i><i class='l'>long</i><i>a</i><i class='l'>a</i><i class='l'>long</i><i>a</i><i>a</i><i>a</i><i>a</i><i>a</i><i>a</i><i>a</i>
</p>
</body>
So to rephrase, my question is how to cause flowing text (like the words in the images above) layout so (a) it fills each row, and (b) each box is a multiple of a square. That is, it snaps to the grid of a square, weather it's 1, 2, 3+ squares, rather than being 2.5 squares or 1.2345 squares or something. It always snaps to a whole block. It does this by first looking at the longer words, and calculating how many blocks it will take up. Then it stretches any shorter blocks (like the one letter "a" in the example above) so as to fill the blank space.
Wondering how this could be done with FlexBox or otherwise with CSS.
Try (I use split 1-3 words depends on length from here )
function show(n) {
text.innerHTML = '<p>' + split(text.innerText,n).map(line=> {
if(line.length==2 && line[0].length<n && line[1].length<n) {
// case for two short words
return `<i class='long'>${line[0]}</i><i class='short'>${line[1]}</i>`
} else {
return line.map(w=>`<i class='${w.length<9 ?'short':'long'}'>${w}</i>`).join('')
}
}).join('') + '</p>';
}
function split(str,n) {
let z=0, b=[], r=[], w=str.split(' ');
let s = w.map(v => v.length < n ? 1 : 2);
s.map((v,i)=>(
z+v>=4 ? (r.push(b),z=0,b=[]) : 0,
z+=v, b.push(w[i])
))
return b.length ? r.concat([b]) : r;
}
show(9) // 9 is min number of letters for long words;
.short {
flex-basis: 64px;
flex-grow: 1
}
.long {
flex-basis: 140px;
flex-grow: 2
}
* {
padding: 0px;
margin: 0px;
text-transform: none;
font-style: normal;
}
p {
display: flex;
flex-wrap: wrap;
width: 260px;
}
i {
flex: 1;
padding: 5px;
margin: 2px;
background: #ddd;
text-align: center;
}
<div id="text">a aaa foo hello congratulations forward interesting place walk to anyplace next sophisticationism aa bb cccccccccc ddd</div>

CSS/JS: split words with horizontal line in responsive design

What would be the best way to split a word in the middle (or after a specific amount of characters or syllables) and join both "word-parts" with a line. Basically imagine a very long flexible underscore.
The goal is to have "word___part" always 100% of the parent container.
Meaning it should work fully responsive when scaling down or up the browser-window.
span:first-child {
float:left;
display:inline-block;
}
span.underscore {
}
span:last-child {
float:right;
display:inline-block;
}
<span>Auto</span><span class="underscore"></span><span>mation</span>
How would you approach that? Flexbox?
Additionally the meta-goal would even be to set the word that is split apart with a dynamic-cms. Meaning the word "Automation" comes from a backend.
You can use :after pseudo-element on first span element and set align-items: flex-end; to align line at bottom of spans.
div {
width: 70%;
display: flex;
}
span:first-child {
display: flex;
align-items: flex-end;
flex: 1;
}
span:first-child:after {
content: '';
height: 1px;
background: black;
flex: 1;
}
<div>
<span>Auto</span><span>mation</span>
</div>
<div>
<span>Lorem ipsum dolor </span><span>sit.</span>
</div>
You can also use js to split string at specific word and wrap each part in span elements.
function modify(selector, word) {
var el = document.querySelector(selector);
var text = el.textContent;
var i = text.indexOf(word)
if (i != -1) {
var arr = [text.substring(0, i), text.substring(i)]
el.innerHTML = arr.map(e => '<span>' + e + '</span>').join('');
}
}
modify('.e1', 'mation')
modify('.e2', 'sit')
div {
width: 70%;
display: flex;
}
span:first-child {
display: flex;
align-items: flex-end;
flex: 1;
}
span:first-child:after {
content: '';
height: 1px;
background: black;
flex: 1;
}
<div class="e1">Automation</div>
<div class="e2">Lorem ipsum dolor sit.</div>
Apply border-bottom to .underscore along with flex-grow: 1, then adjust height and margins to fit.
.wrapper {
display: flex;
}
span.underscore {
border-bottom: 2px solid black;
flex-grow: 1;
height: 0.5em;
margin: 0 5px;
}
<div class="wrapper">
<span>Auto</span><span class="underscore"></span><span>mation</span>
</div>
You can even use a dotted border instead of solid to simulate ellipses.
A pretty simple way:
<div>
<span class="left">Auto</span>
<span class="underscore"></span>
<span class="right">mation</span>
</div>
div {
display: flex;
}
.underscore {
width: 100%;
border-bottom: 1px solid #000;
margin: 0 5px;
}
https://codepen.io/anon/pen/XaddqO
In case if background-color behind text element is a solid color:
Create background-image with linear-gradient() on parent.
Override background-color on child elements.
Working Demo:
.text {
background: linear-gradient(to top, transparent 5px, black 5px,
black 7px, transparent 7px);
justify-content: space-between;
display: flex;
}
.text span {
background: #fff;
padding: 0 5px;
}
<div class="text">
<span>Auto</span>
<span>mation</span>
</div>
The answers are good but you said Additionally the meta-goal would even be to set the word that is split apart with a dynamic-cms. Meaning the word "Automation" comes from a backend.
So yiu can use the getword() method to get the word from backend and separate it into two using javascript
You can try to run the snippet and see the output. Then change the string returned by the getword() method and run again.
var container = document.getElementById('slit-container');
var word = getWord();
var wordPartOne = word.substring(0, 4);
var wordPartTwo = word.substring(4, word.lenght);
var data = "<span>"+wordPartOne+"</span> <span>"+wordPartTwo+"</span>";
container.innerHTML = data;
function getWord(){
//Query your backend to get the word
//for test purpose I will just return a string
return "Automation"
}
div {
width: 70%;
display: flex;
}
span:first-child {
display: flex;
align-items: flex-end;
flex: 1;
}
span:first-child:after {
content: '';
height: 1px;
background: black;
flex: 1;
}
<div id="slit-container">
</div>

Categories

Resources