Skip to content

Commit

Permalink
feat(web): create custom <Button /> component implementation (#1533)
Browse files Browse the repository at this point in the history
  • Loading branch information
kantord authored Sep 23, 2021
1 parent 46699a1 commit 4eaa077
Show file tree
Hide file tree
Showing 33 changed files with 321 additions and 267 deletions.
158 changes: 101 additions & 57 deletions apps/lluis/Button.svelte
Original file line number Diff line number Diff line change
@@ -1,74 +1,118 @@
<script lang="typescript">
import { createEventDispatcher } from "svelte"
import LinkOrButton from "./primitives/LinkOrButton.svelte"
import Icon from "lluis/Icon.svelte"

const dispatch = createEventDispatcher()
export let primary = false
export let light = false
export let info = false
export let inverted = false
export let outlined = false
export let hidden = false
export let color = null
export let textColor = null
export let customColor = color != null
export let customTextColor = textColor != null
export let size = "default"
export let type = "button"
export let tabindex = 0
export let key = false
export let disabled = false
export let href: string | null = null
export let size: "small" | "normal" | "medium" | "large" = "normal"
export let loading = false
export let asHref: string | null = null
export let submit = false

let styleTokens = `
--color:${color};
--textColor:${textColor};
`
export let type: "button" | "submit" = "button"
export let style: "primary" | "secondary" | "key" = "secondary"
export let target: string | undefined = undefined
export let tabIndex: number | undefined = undefined
export let disabled = false
</script>

<button
style="{styleTokens}"
class="button is-{size}"
class:is-primary="{primary}"
class:is-light="{light}"
class:is-info="{info}"
class:is-inverted="{inverted}"
class:is-outlined="{outlined}"
class:is-hidden="{hidden}"
class:is-loading="{loading}"
class:customColor
class:customTextColor
class:key
on:click="{() => dispatch('click')}"
{tabindex}
{disabled}
{type}>
<slot />
</button>
{#if asHref}
<a class="is-hidden" href={asHref}>{asHref}</a>
<div class="lluis-button" class:small={size === "small"} class:large={size === "large"} data-style={style}>
<LinkOrButton href={href} on:click="{() => dispatch('click')}" type={type} target={target} tabIndex={tabIndex} disabled={disabled}>
{#if loading}
<span class="spinner">
<Icon icon="spinner" />
</span>
{:else}
<slot />
{/if}
</LinkOrButton>
</div>

{#if asHref != null}
<a class="hidden-link" href={asHref} />
{/if}

<style type="text/scss">
.button.customColor {
background-color: var(--color);
@keyframes spinner {
to {transform: rotate(360deg);}
}

.lluis-button {
display: inline-block;
}

.button.customTextColor {
color: var(--textColor);
div>:global(*) {
display: flex;
border-radius: var(--button-radius-small);
padding: 6px 20px;
margin: 4px;
transition-property: filter;
transition-duration: .1s;
transition-timing-function: ease-in-out;

:global(.icon) {
width: unset;
height: unset;
margin-right: 8px;
}

&:hover, &:focus {
filter: brightness(1.2);
}

&:active {
filter: brightness(.9);
transform: scale(0.9);
}
}

.key {
font-family: monospace;
border-radius: 8px;
text-transform: none;
margin: 1em;
margin-left: 0;
margin-top: 0;
.spinner {
display: flex;
width: 16px;
height: 16px;
align-items: center;
justify-content: center;
animation: spinner .6s linear infinite;

:global(.icon) {
display: block;
margin: 0 !important;
}
}
</style>

{#if submit}
<button type="submit" class="is-hidden"></button>
{/if}
div[data-style=primary]>:global(*) {
border: 1px solid var(--button-primary-border);
color: var(--button-primary-text-color) !important; /* TODO: remove when hero is remoevd */
background-color: var(--button-primary-background-color) !important;
}

div[data-style=secondary]>:global(*) {
border: 1px solid var(--button-secondary-border);
color: var(--button-secondary-text-color) !important;
background-color: var(--button-secondary-background-color) !important;
}

div[data-style=key]>:global(*) {
margin: 6px;
padding: 6px 0;
text-align: center;
width: calc(1em + 22px);
border: 1px solid var(--button-key-border);
color: var(--button-key-text-color) !important;
background-color: var(--button-key-background-color) !important;
}

.small>:global(*) {
font-size: 16px;
padding: 3px 12px;
}

.medium>:global(*) {
font-size: 18px;
padding: 3px 12px;
}

.large>:global(*) {
font-size: 20px;
padding: 9px 14px;
}
</style>
61 changes: 0 additions & 61 deletions apps/lluis/ButtonLink.svelte

This file was deleted.

10 changes: 10 additions & 0 deletions apps/lluis/Hidden.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div>
<slot />
</div>


<style>
div {
display: none !important;
}
</style>
2 changes: 1 addition & 1 deletion apps/lluis/Icon.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="typescript">
export let size = "medium"
export let prefix = "fas"
export let icon
export let icon: string
export let left = false
</script>

Expand Down
10 changes: 7 additions & 3 deletions apps/lluis/primitives/LinkOrButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@

const dispatch = createEventDispatcher()
export let href: string | null = null
export let type: "button" | "submit" = "button"
export let target: string | undefined = undefined
export let tabIndex: number | undefined = undefined
export let disabled = false
</script>

{#if href !== null}
<a href={href} {...$$restProps}>
<a href={href} target={target} tabindex="{tabIndex}" {...$$restProps}>
<slot />
</a>
{/if}

{#if href === null}
<button on:click={() => dispatch("click")} {...$$restProps}>
<button type={type} tabindex="{tabIndex}" disabled={disabled} on:click={() => dispatch("click")} {...$$restProps}>
<slot />
</button>
{/if}

<style type="text/scss">
button {
display: block;
display: inline-block;
background: transparent;
border: 0;
font-size: inherit;
Expand Down
2 changes: 1 addition & 1 deletion apps/web/cypress/integration/common/i_click.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ Then("I click {string}", (text) => {
})

Then("I click the {string} button", (text) => {
cy.get("button, .button").contains(text).click()
cy.get(".lluis-button").contains(text).click()
})
6 changes: 3 additions & 3 deletions apps/web/cypress/integration/common/i_see_button.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Given } from "cypress-cucumber-preprocessor/steps"

Given(/I see an? "(.*)" button/, (text) => {
cy.get(".button").contains(text).should("be.visible")
cy.get(".lluis-button").contains(text).should("be.visible")
})

Given(/I don't see an? "(.*)" button/, (text) => {
cy.get(".button").contains(text).should("not.exist")

cy.get(".lluis-button").contains(text).should("not.exist")
})
16 changes: 8 additions & 8 deletions apps/web/cypress/integration/common/virtual_keyboard.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { Then } from "cypress-cucumber-preprocessor/steps"

Then("I see a virtual keyboard with {int} keys", n => {
cy.get(".keyboard")
.find(".key")
cy.get(".virtual-keyboard")
.find(">*")
.should("have.length", n)
})

Then("the keys on the virtual keyboard have proper labels", () => {
cy.get(".keyboard")
.find(".key")
cy.get(".virtual-keyboard")
.find(">*")
.contains("á")
.should("be.visible")
})

Then("clicking on a key types into the input field", () => {
cy.get(".keyboard")
.find(".key")
cy.get(".virtual-keyboard")
.find(">*")
.contains("á")
.click()
cy.get("input").should("have.value", "á")
})

Then("the virtual keyboard is inactive", () => {
cy.get(".keyboard")
.find(".key")
cy.get(".virtual-keyboard")
.find(">*")
.contains("á")
.should("be.disabled")
})
4 changes: 4 additions & 0 deletions apps/web/cypress/integration/introductionPage.feature
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Feature: Skill introduction page
And I click "Learn Animals"
Then I should be on "/course/test/skill/animals/introduction"
Then I read "Introduction to animals"

Scenario: Practicing the skill from the introduction page
When I open "/course/test/skill/animals/introduction"
Then I read "Introduction to animals"
When I click "Practice Animals"
Then I should be on "/course/test/skill/animals"

Expand Down
6 changes: 1 addition & 5 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
"installAllExternalCourses": "./scripts/installExternalCourses.sh",
"fetchPhotos": "./scripts/fetchPhotos.sh",
"fetchAudios": "./scripts/fetchAudios.sh",
"updateAllCourseData": "./scripts/updateAllCourseData.sh",
"downloadCourseData": "heroku run -a librelingo-course-editor python manage.py dumpdata course --indent=2 > ./dumps/courseData.json",
"loadCourseDataLocally": "yarn downloadCourseData && cd ../../ && rm -f db.sqlite3 && python manage.py migrate && python manage.py loaddata ./apps/web/dumps/courseData.json && cd -",
"exportCourse": "yarn loadCourseDataLocally && cd ../../ && pipenv run python manage.py exportcourse $1",
"percypress": "sh ./percypress.sh",
"test": "yarn dev & yarn percypress",
"test:ci": "npx serve __sapper__/export -l 3000 & yarn percypress",
Expand All @@ -31,7 +27,7 @@
"prettiercheck:src": "prettier --plugin-search-dir=. ./src/**/*.js",
"prettiercheck:cypress": "prettier --plugin-search-dir=. ./cypress/**/*.js",
"prettiercheck:svelte": "prettier --plugin-search-dir=. ./src/**/*.svelte",
"eslintcheck": "eslint ./src"
"eslintcheck": "eslint ./src && eslint ./cypress"
},
"publishConfig": {
"access": "public"
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
faLock,
faEnvelope,
faHeart,
faSpinner
} from "@fortawesome/free-solid-svg-icons"
import { faTwitter } from "@fortawesome/free-brands-svg-icons"

Expand All @@ -23,6 +24,7 @@ library.add(faUser)
library.add(faLock)
library.add(faEnvelope)
library.add(faHeart)
library.add(faSpinner)
dom.watch()

sapper.start({
Expand Down
Loading

0 comments on commit 4eaa077

Please sign in to comment.