Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                .container
  #table
  #calculator
              
            
!

CSS

              
                @import 'breakpoint';
/* Fonts */
@import url('https://fonts.googleapis.com/css?family=Poppins:500,600');

$stackPoppins: 'Poppins', sans-serif;

/* Colors */
$sign: #bcb5b4;
$name: #fff6f4;
$panel: #e5dddc;
$squareButton: #bfb8b7;
$textDarkButton: #c1bab9;
$nail: #e1dad9;
$darkGray: #403d3d;
$darkViolet: #40293D;
$shadow: rgba(0, 0, 0, .5);
$authorName: #9c6895;
/* Breakpoints */
$lg: 1200px;
$md: 992px 1199px;
$sm: 768px 991px;
$xs: max-width 767px;
$xxs: max-width 449px;

/* Grid */

/* Customs */
body, html {
  min-height: 100%;
   & * {
    outline: 0;
    border: 0;
    margin: 0;
    padding: 0;
    text-decoration: none;
    box-sizing: border-box;
    &:active {
      outline: 0;
    }
    &:focus {
      outline: 0;
    }
  }
}
body {
  font: {
    family: $stackPoppins;
    size: 16px;
  }
  line-height: 135%;
  font-size-adjust: 100%;
  word-break: break-word;
  hyphens: auto;
  -webkit-hyphenate-after: 3;
  -webkit-hyphenate-before: 2;
  hyphenate-lines: 3;
  padding: 10% 5%;
  background-color: #fefefe;
  background: #fefefe url('https://img4.goodfon.ru/wallpaper/nbig/5/ee/kirpich-stena-testura-1.jpg') repeat center;
  background-size: 150px 150px;
}

button {
  cursor: pointer;
}

.table {
  width: 30%;
  max-width: 300px;
  min-width: 260px;
  min-height: 175px;
  padding: 55px 0 0; 
  text-align: center;
  transform: rotate(15deg);
  background-color: $darkGray;
  margin: 0 auto;
  line-height: 200%;
  position: relative;
  box-shadow: -5px -7px 10px $shadow;
}

.sign {
  color: $sign;
  font-size: (23em / 16);
}

.nameAuthor {
  font-size: (15em / 16);
  color: $authorName;
  transition: color 0.5s;
  &:hover {
    text-decoration: none;
    color: darken($authorName, 10%);
  }
}

.table__nail {
  position: absolute;
  background-color: $nail;
  width: 250% * 1.6 / 100;
  height: 219% * 2.5 / 100;
  border-radius: 50%;
  box-shadow: -1px -6px 5px $shadow;
  &::after {
    content: "";
    position: absolute;
  }
  &::after {
    box-shadow: inset 0 0 15px $shadow;
    top: 40%;
    left: 5%;
    width: 90%; 
    height: 2px;
  }
}

.table__nail-topRight, .table__nail-topLeft {
  top: 219% * 1 / 100 ;
}
.table__nail-bottomLeft, .table__nail-bottomRight {
  bottom: 219% * 1 / 100 ;;
}
.table__nail-topRight, .table__nail-bottomRight {
   right: 250% * 1 / 100;
}
.table__nail-topLeft, .table__nail-bottomLeft {
  left: 250% * 1 / 100;
}
.table__nail-topLeft {
  &::after { 
    transform: rotate(25deg);
  }
}
.table__nail-topRight {
  &::after { 
    transform: rotate(-10deg);
  }
}

.table__nail-bottomRight {
  &::after { 
    transform: rotate(45deg);
    top: 40%;
    left: 18%;
    width: 75%;
  }
}

.table__nail-bottomLeft {
  &::after { 
    transform: rotate(-35deg);
    width: 80%;
    left: 10%;
  }
}
.calculator, #caclculator {
  max-width: 600px;
  height: 455px;
}

#calculator {
  margin-top: 15%;
  @include breakpoint($xs) {
    margin: 15% -15px 0; 
  }
}
.calculator {
  margin: 0 auto;
  transform-style: preverse-3d;
  perspective: 500px;
}
.calculator__header, .calculator__body {
  background-color: $darkGray;
  width: 100%;
}
.calculator__header, .panel {
  margin: 0 auto;
  border-top-right-radius: 20px;
  border-top-left-radius: 20px;
}

// Header
.calculator__header {
  height: 40%;
  transform: rotateX(10deg);
  width: 87.5%;
  margin-bottom: -24px;
  box-shadow: 0 -42px 47px $shadow, inset 0 -5px 30px 5px $shadow;
}
// Name
.name {
  padding: 4% 0px 3%;
  color: $name;
  font-size: (19em / 16);
}

// Panel
.panel {
  width: 80%;
  height: 50%;
  border-radius: 15px;
  background-color: $panel;
  border-bottom-left-radius: 11px;
  border-bottom-right-radius: 11px;
  box-shadow: inset 0 -4px  29px $shadow;
  padding: 4%;
  color: $textDarkButton;
}

.panel__action {
  height: 55%;
  border-bottom: 1px solid $textDarkButton;
}
.panel__result {
  height: 45%;
}

// Body
.calculator__body {
  height: 70%;
  transform: rotateX(20deg);
  box-shadow:  inset 0 10px 30px 5px $shadow;
  border-bottom-left-radius: 15px;
  border-bottom-right-radius: 15px;
}

.leftSideDial, .rightSideDial {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-around;
  align-items: center;
}
.leftSideDial {
  width: 60%;
  padding: 3% 0 0 4.5%;
  float: left;
  @include breakpoint($xs) {
    padding-bottom: 9%;
  }
}
.rightSideDial {
  width: 40%;
  padding: 1% 5% 0 0;
}

.leftSideDial__btn, .rightSideDial__btn {
    margin: 10px 21px;
    font: {
      weight: 900;
      size: (23em / 16)
    }
    box-shadow: 0 9px 9.7px 0.3px $shadow;
    &:active {
      top: 3px;
      box-shadow: 0 2px 11px 1px $shadow;
    }
     box-shadow: 0 9px 9.7px 0.3px $shadow;
    position: relative;
    transition: background-color 0.5s, top  1.5s, box-shadow 0.1s;
  
    @include breakpoint($xs) {
      margin: 10px 14px;
    }
  
    @include breakpoint($xxs) {
      margin: 10px 10px;
    }
}

.leftSideDial__btn--square {
  padding: 5% 7.5%;
  color: $darkGray;
  background-color: $squareButton;
  &:hover {
    background-color: darken($squareButton, 10%);
  }
  
  @include breakpoint($xs) {
    padding: 4% 5.5%;
  }
}
.leftSideDial__btn--clean, .rightSideDial__btn--math {
  background-color: $darkViolet;
  color: $squareButton;
  &:hover {
    background-color: darken($darkViolet, 5%);
  }
}

.leftSideDial__btn--clean {
  border-radius: 75%;
  padding: 4%;
  @include breakpoint($xs) {
    padding: 3% 4.5%;
  }
}
.leftSideDial__btn--actClean {
  order: 2;
}
.leftSideDial__btn--square_0 {
  order: 1;
}
.rightSideDial__btn--math {
  border-radius: 50%;
  padding: 3% 0;
  max-width: 54px;
  min-width: 54px;
  text-align: center;
  margin: 35px 9px 0;
  @include breakpoint($xs) {
    min-width: 47px;
    max-width: 47px;
  }
}
              
            
!

JS

              
                // Table
class Table extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div className="table">
       <Sign />
       <Nail position="tr" />
       <Nail position="tl" />
       <Nail position="br" />
       <Nail position="bl" />
     </div>
    );
  }
}

class Nail extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const positions = {
      tl: "table__nail-topLeft",
      tr: "table__nail-topRight",
      bl: "table__nail-bottomLeft",
      br: "table__nail-bottomRight"
    };

    return (
      <div className={"table__nail " + positions[this.props.position]} />
    );
  }
}

function Sign(props) {
  return (
    <p className="sign">
       Disigned and Coded
      <br />
      <a className="nameAuthor" href="https://www.freecodecamp.com/wishez">
        by Filipp Zhuravlev
      </a>
    </p>
  );
}

// Calculator
class Calculator extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="calculator">
       <Header />
       <Body />
     </div>
    );
  }
}

function Header(props) {
  return (
    <div className="calculator__header">
        <h3 className="name text-center">
          JavaScript Calculator 
        </h3>
       <Panel />
    </div>
  );
}
class Panel extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: this.props.action,
      resultValue: ''
    }
  }

  render() {
    this.state.resultValue += ' ' + this.state.value;
    return (
      <div className="panel">  
        <p className="panel__action" id='actionPanel' />
        <p className="panel__result" id='resultPanel' />
      </div>
    );
  }

}

function Body(props) {
  const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
    operators = ['+', '-', '*', '/', '%', '.', '='];
  return (
    <div className="calculator__body">
      <Dial numbers={numbers} operators={operators} />      
    </div>
  );
}

function Dial(props) {
  return (
    <div className="dial">
      <LeftSideDial numbers={props.numbers} />
      <RightSideDial operators={props.operators} />
    </div>
  );
}

function LeftSideDial(props) {
  return (
    <div className="leftSideDial">
      {props.numbers.map((num, i) =>  <NumButton key={i} number={num} />)}
      <CleanButton name='AC' func='allClean' />
      <CleanButton name='CE' func='actClean' />
    </div>
  );
}

function RightSideDial(props) {
  return (
    <div className="rightSideDial" >
        {props.operators.map((op, i) =>  <MathButton key={i} operator={op} />)}
    </div>
  );
}

class NumButton extends React.Component {
  constructor(props) {
    super(props);

    this.showAct = this.showAct.bind(this);
  }
  
  showAct = showAct;

  render() {
    return (
      <button className={"leftSideDial__btn leftSideDial__btn--square leftSideDial__btn--square_" + this.props.number} onClick={this.showAct}>
        {this.props.number}
      </button>
    );
  }
}

class CleanButton extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      allClean: this.cleanAllOnPanel,
      actClean: this.cleanActOnPanel
    };

    this.cleanALlOnPanel = this.cleanAllOnPanel.bind(this);
    this.cleanActOnPanel = this.cleanActOnPanel.bind(this);
  }

  // Clean a last symbol on the panel's bottom row and a symbol on the panel's top row.
  cleanAllOnPanel() {
      $('#resultPanel')[0].innerHTML = '';
      $('#actionPanel')[0].innerHTML = '';
    }
    // Destroyed charcters from the calculator's panel.
  cleanActOnPanel() {
    let $resultPanel = $('#resultPanel'),
      resultText = $resultPanel[0].innerHTML,
      textLen = resultText.length;
    $resultPanel[0].innerHTML = resultText.slice(0, resultText[textLen - 1] === ' ' ? textLen - 2 : textLen - 1);
    $('#actionPanel')[0].innerHTML = '';
  }

  render() {
    const actCleanModifyer = this.props.func === 'actClean' ? 'leftSideDial__btn--actClean' : '';
    return (
      <button className={"leftSideDial__btn leftSideDial__btn--clean " + actCleanModifyer} onClick={this.state[this.props.func]} >
         {this.props.name}
      </button>
    );
  }
}

class MathButton extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      '+': ['plus', this.showAct],
      '-': ['minus', this.showAct],
      '*': ['multiply', this.showAct],
      '/': ['division', this.showAct],
      '%': ['remaind', this.showAct],
      '.': ['float', this.showAct],
      '=': ['equal', this.calculate]
    };

    this.showAct = this.showAct(this);
    this.calculate = this.calculate.bind(this);
  }

  showAct = showAct;

  calculate(e) {
    showAct(e);
    let $resultPanel = $('#resultPanel'),   
        resultText = $resultPanel.text();
    
    $resultPanel.html(resultText.slice(0, resultText.length - 2));
    
  }

  render() {
    return (
      <button className={'rightSideDial__btn rightSideDial__btn--math rightSideDial__btn--math_' + this.state[this.props.operator][0]} onClick={this.state[this.props.operator][1]}> 
        {this.props.operator}
      </button>
    );
  }
}

ReactDOM.render(<Table />, document.getElementById('table'));
ReactDOM.render(<Calculator />, document.getElementById('calculator'));

// Show act under and above the gray devider on the claculator's panel.
function showAct(e) {
  let $resultPanel = $('#resultPanel'),
    $actPanel = $('#actionPanel'),
    actText = $(e.target).text(),
    oldResultText = $resultPanel.text(),
    lastAct = oldResultText.charAt(oldResultText.length - 1),
    newResultText = fixString(oldResultText, lastAct, actText);
  
    
  
  $actPanel.html(actText);

  $resultPanel.html(intermediateCalculate(newResultText));
};

// Fix string.
// str is old text on the bottom row of the panel.
// previousAct is a last symbol the panel's bottom row.
// act is current action, it can be number or any math operator.
function fixString(str, previousAct, act) {
  let isNum = /[0-9]+/,
      newStr = '';
  // Remove spaces between numbers and add spaces between numbers and math operators.
  if ((isNum.test(previousAct) &&
      isNum.test(act)) ||
      act == '' ||
      (!isNum.test(previousAct) &&
      isNum.test(act)))
    newStr = isNum.test(previousAct) && isNum.test(act) || previousAct === '.' ? str + act : str + ' ' + act;
  else
    // Don't repeat math operators.
    newStr = !isNum.test(previousAct) ? str.replace(previousAct, act) : str + ' ' + act;
  
  // Experession can't start with a math operator.
  newStr = isNum.test(newStr[0]) ? newStr : newStr.slice(1);

  // Fix dots.
  if (act === '.') {
    // Remove spaces after, befor, and both sides.
    newStr = newStr
      .replace(/\s\.\s/, '.')
      .replace(/\.\s/, '.')
      .replace(/\s\./, '.');
                                
    
    // Remove extra dots.
    newStr = newStr
      .split(' ')
      // Pass through each a literal of expression.
      .map(a => {
        let isDot = a.indexOf('.');
        
        if (isDot !== -1) {
          // We need only one dot.
          a = a.replace(new RegExp(/\./, 'g'), '');
          
          return a.slice(0, isDot) + '.' + a.slice(isDot);
        }

        return a;
      })
      .join(' '); 
  }
  
  return newStr;
}

const mathActions = {
  '+': (a, b) => {
    return +a + +b;
  },
  '-': (a, b) => {
    return +a - +b;
  },
  '*': (a, b) => {
    return +a * +b;
  },
  '/': (a, b) => {
    return +a / +b;
  },
  '%': (a, b) => {
    return +a % +b;
  }
};

function intermediateCalculate(str) {
  let operators = /[+\-*/%=]/,
      expression = str.split(' ');
  
  if (expression.length === 4) {
    return mathActions[expression[1]](expression[0], expression[2]) + ' ' + expression[3];
  }
  
  return str;
}

$(function() {
  
  $('.nameAuthor').click((e)=> {
    let url = $(e.target).attr('href');
    
    window.open(url);
    
    return false;
  });// end click
  $(window).scroll(function() {
    let $this = $(this),
      scrolled = $this.scrollTop(),
      screenWidth = $this.innerWidth(),
      calcStyle = $('.calculator')[0].style,
      bodyStyle = $('body')[0].style,
      isMDScreen = screenWidth > 992 && screenWidth < 1199,
      isSMScreen = screenWidth > 769 && screenWidth < 991,
      isXSScreen = screenWidth > 460 && screenWidth < 768,
      isXXSScreen = screenWidth < 459;
    
    if (scrolled > 130) {
      calcStyle.position = 'fixed';
      calcStyle.bottom = '41px';
      bodyStyle.paddingBottom = '100%';
     
      if (isMDScreen) 
        calcStyle.left = '25vw';
      else if (isSMScreen) 
        calcStyle.left = '17vw'; 
      else if (isXSScreen)
        calcStyle.left = '12vw';
      else if (isXXSScreen) {
        calcStyle.left = '7vw';
        bodyStyle.paddingBottom = '200%';
      }
      else
        calcStyle.left = '30vw';
      
    } else {
      calcStyle.position = 'static';
      bodyStyle.paddingBottom = '10%';
    }

  });
});
              
            
!
999px

Console