<div class="a-progress">
    <small class="a-progress__max">&nbsp;CHF</small>
    <div class="a-progress__container">
        <div class="a-progress__bar" role="progressbar" style="width: 28%" aria-valuenow="14000" aria-valuemin="1" aria-valuemax="50000">
            <span class="a-progress__current a-progress__current--right">
                <span class="a-progress__value">14000</span>&nbsp;CHF
            </span>
        </div>
    </div>
</div>
<div class="a-progress">
		{{#if legend}}
				<p class="a-progress__legend"><strong><span class="a-progress__legend-value">{{current}}</span> haben unterschrieben.</strong> Erreichen wir {{goal}}?</p>
		{{else}}
			<small class="a-progress__max">{{max}}{{#if unit}}&nbsp;{{unit}}{{/if}}</small>
		{{/if}}
    <div class="a-progress__container">
        <div
                class="a-progress__bar"
                role="progressbar"
                style="width: {{current_percent}}%"
                aria-valuenow="{{current}}"
                aria-valuemin="{{min}}"
                aria-valuemax="{{goal}}"
				>
						<span class="a-progress__current{{#if low_counter}} a-progress__current--right{{/if}}">
							<span class="a-progress__value">{{ current }}</span>{{#if unit}}&nbsp;{{unit}}{{/if}}
						</span>
				</div>
    </div>
</div>
  • Content:
    .a-progress {
    	margin: 1em 0;
    	width: 100%;
    
    	&__container {
    		width: 100%;
    		height: 2.5rem;
    		background: $color-grey-1;
    		overflow: hidden;
    	}
    
    	&__bar {
    		background: $color-primary;
    		height: 100%;
    		position: relative;
    		transition: opacity $transition-mid $transition-ease;
    
    		@include high-contrast {
    			background: $color-primary-dark;
    		}
    
    		&::after {
    			content: ' ';
    			display: block;
    			background-color: white;
    			width: 1px;
    			height: 110%;
    			transform: rotateZ(8deg);
    			opacity: 0.1;
    			box-shadow: 0 0 1em 0.75em white;
    			position: absolute;
    
    			animation-iteration-count: infinite;
    			animation-timing-function: $transition-ease;
    			animation-duration: 2.5s;
    			animation-name: flash;
    
    			@keyframes flash {
    				from {
    					left: -1000%;
    				}
    
    				75% {
    					left: 0
    				}
    
    				to {
    					left: 100%
    				}
    			}
    		}
    	}
    
    	&__max {
    		display: block;
    		width: 100%;
    		text-align: right;
    		padding-bottom: 0.125em;
    		color: $color-text-light;
    		font-size: 0.875rem;
    	}
    
    	&__current {
    		position: absolute;
    		right: 0.5em;
    		top: 50%;
    		transform: translateY(-50%);
    		color: $color-white;
    		font-weight: $font-weight-bold;
    		font-size: 1.4rem;
    		transition: opacity $transition-mid $transition-ease;
    	}
    
    	&__current--right {
    		right: -0.5em;
    		transform: translateY(-50%) translateX(100%);
    		color: $color-text-light;
    
    		@include high-contrast {
    			color: $color-text;
    		}
    	}
    
    	&__legend {
    		line-height: 1.4em;
    		margin: 0 0 0.25em;
    		transition: opacity $transition-mid $transition-ease;
    	}
    }
    
    .a-progress--loading {
    	.a-progress {
    		&__legend {
    			opacity: 0;
    		}
    
    		&__current {
    			opacity: 0;
    		}
    
    		&__bar {
    			opacity: 0;
    		}
    	}
    }
    
  • URL: /components/raw/a-progress/_a-progress.scss
  • Filesystem Path: styleguide/src/components/atoms/a-progress/_a-progress.scss
  • Size: 1.7 KB
  • Content:
    import BaseView from 'base-view';
    import inView from '../../../js/service/inview';
    import ajax from '../../../js/service/ajax';
    
    const BAR_SELECTOR = '.a-progress__bar';
    const VALUE_SELECTOR = '.a-progress__value';
    const LEGEND_SELECTOR = '.a-progress__legend';
    const LEGEND_VALUE_SELECTOR = '.a-progress__legend-value';
    
    const LOADING_CLASS = 'a-progress--loading';
    
    const DEBOUNCE_DELAY_MS = 300;
    const STEPS = 200;
    const STEP_DELAY = 25; // ms
    
    // sync with m-form.js
    const SUBMISSION_NOTIFICATION_EVENT = 'supt_form_submission';
    
    export default class AProgress extends BaseView {
    	bind() {
    		super.bind();
    
    		this.firstRun = true;
    		this.bar = this.getScopedElement( BAR_SELECTOR );
    
    		this.listenForSubmissions();
    
    		this.updateData().finally( () => {
    			inView( this.element, DEBOUNCE_DELAY_MS ).
    				then( () => this.startAnimation() );
    		} );
    	}
    
    	updateData() {
    		if (!( 'url' in this.bar.dataset )) {
    			return new Promise( resolve => resolve() );
    		}
    
    		const url = this.bar.dataset.url;
    		return ajax( url, 'GET' ).then( ( resp ) => {
    			if (resp instanceof Object
    				&& 'current' in resp
    				&& 'goal' in resp
    				&& 'legend' in resp
    			) {
    				this.bar.setAttribute( 'aria-valuenow', resp.current );
    				this.bar.setAttribute( 'aria-valuemax', resp.goal );
    				this.getScopedElement( LEGEND_SELECTOR ).innerHTML = resp.legend;
    			}
    		} );
    	}
    
    	startAnimation() {
    		this.value = this.getScopedElement( VALUE_SELECTOR );
    		this.legend_value = this.getScopedElement( LEGEND_VALUE_SELECTOR );
    
    		this.min = this.bar.getAttribute( 'aria-valuemin' );
    		this.max = this.bar.getAttribute( 'aria-valuemax' );
    		this.current = this.bar.getAttribute( 'aria-valuenow' );
    
    		if (this.firstRun) {
    			this.step_count = 0;
    			this.state = 0;
    			this.state_percent = 0;
    		}
    
    		this.sumOfSteps = 1 / 2 * STEPS * ( STEPS + 1 );
    		this.spread = this.current - this.min;
    
    		this.timer = setInterval( this.animate.bind( this ), STEP_DELAY );
    	}
    
    	addSubmission() {
    		this.updateData().then( this.startAnimation.bind( this ) );
    	}
    
    	animate() {
    		if (this.firstRun) {
    			this.removeClass( this.element, LOADING_CLASS );
    			this.firstRun = false;
    		}
    
    		if (this.step_count > STEPS) {
    			clearInterval( this.timer );
    
    			// we need this extra step to circumvent float calculation errors
    			const current = ( this.spread / ( this.max - this.min ) );
    			this.bar.style.width = current * 100 + '%';
    			this.setLabelValue( this.current );
    
    		}
    		else {
    
    			this.step_count ++;
    
    			const easing = ( STEPS - this.step_count ) / this.sumOfSteps;
    			const step_size = this.spread * easing;
    			const step_percent = step_size / ( this.max - this.min );
    
    			this.state += step_size;
    			this.state_percent += step_percent;
    
    			this.bar.style.width = this.state_percent * 100 + '%';
    			this.setLabelValue( Math.round( this.state ) );
    		}
    	}
    
    	setLabelValue( value ) {
    		if (this.legend_value) {
    			this.legend_value.innerText = value;
    		}
    
    		this.value.innerText = value;
    	}
    
    	listenForSubmissions() {
    		document.addEventListener( SUBMISSION_NOTIFICATION_EVENT, event => {
    			if (!( 'form' in this.bar.dataset )) {
    				return;
    			}
    
    			const progressFormId = parseInt( this.bar.dataset.form );
    			const eventFormId = parseInt( event.detail.formId );
    
    			if (progressFormId === eventFormId) {
    				this.addSubmission();
    			}
    		} );
    	}
    
    	destroy() {
    		window.removeEventListener( 'scroll', this.eventHandler );
    		window.removeEventListener( 'resize', this.eventHandler );
    
    		super.destroy();
    	}
    }
    
  • URL: /components/raw/a-progress/a-progress.js
  • Filesystem Path: styleguide/src/components/atoms/a-progress/a-progress.js
  • Size: 3.5 KB
{
  "min": 1,
  "goal": 50000,
  "current": 14000,
  "current_percent": 28,
  "unit": "CHF",
  "low_counter": true
}

No notes defined.