Skip to content

Commit

Permalink
💄 [#1309] Added file-input toggle, file info and file error styles
Browse files Browse the repository at this point in the history
  • Loading branch information
jiromaykin committed Apr 23, 2023
1 parent 0bd2642 commit 204d608
Show file tree
Hide file tree
Showing 15 changed files with 431 additions and 47 deletions.
2 changes: 1 addition & 1 deletion src/open_inwoner/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ def __init__(self, users, *args, **kwargs):

class CaseUploadForm(forms.Form):
title = forms.CharField(
label=_("Titel"), max_length=255, validators=[validate_charfield_entry]
label=_("Titel bestand"), max_length=255, validators=[validate_charfield_entry]
)
type = forms.ModelChoiceField(
ZaakTypeInformatieObjectTypeConfig.objects.none(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
title="{% firstof title text %}"
aria-label="{% firstof title text %}"
{% as_attributes extra_attributes %}
{% if id %} id="{{ id }}" {% endif %}
>
{% if icon %}{% icon icon=icon outlined=icon_outlined %}{% endif %}
{% if text_icon %}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% load i18n form_tags button_tags icon_tags %}

<div class="form__control {{ extra_classes|default:"upload" }}">
<div id="inputfile-group" class="inputfile-group">
<label class="label">
<span class="input-file">
{{ field|addclass:"inputfile" }}

<label class="label__label">
{% icon icon="cloud_upload" icon_position="before" outlined=True %}
{{ text }}
{% if field.field.required %}<span class="label__label--required"> * </span>{% endif %}
</label>
</span>

{% if field.errors %}
{% errors errors=field.errors %}
{% endif %}
</label>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
hx-select="{{ async_selector }}"
hx-target="{{ async_selector }}"
{% endif %}

{# HTML attribute to bypass browser defaults and show validation #}
novalidate
>
{% if form.non_field_errors %}
{% errors errors=form.non_field_errors %}
Expand Down
16 changes: 16 additions & 0 deletions src/open_inwoner/components/templatetags/form_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,22 @@ def input(field, **kwargs):
return {**kwargs, "field": field}


@register.inclusion_tag("components/Form/FileInput.html")
def file_input(file, text, **kwargs):
"""
Displaying a file upload interface.
Usage:
{% file_input form.field text="Bestanden uploaden" %}
Variables:
+ field: Field | The field that needs to be rendered.
- extra_classes: string| classes which should be added to the top-level container
"""
kwargs["text"] = text
return {**kwargs, "field": file}


@register.inclusion_tag("components/Form/DateField.html")
def date_field(field, **kwargs):
return {**kwargs, "field": field}
Expand Down
1 change: 1 addition & 0 deletions src/open_inwoner/js/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import './preview'
import './questionnaire'
import './search'
import './toggle'
import './upload-document'
import './session'

const htmx = (window.htmx = require('htmx.org'))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const documentUpload = document.getElementById('formOpenUpload')
const uploadError = document.querySelectorAll('.notifications')
// get info
const getFormInfo = document.querySelectorAll('.form__control--info')

// if errors are present, scroll and trigger opened state
if (uploadError.length > 1) {
console.log(uploadError)
documentUpload.scrollIntoView({
block: 'center',
behavior: 'smooth',
})
documentUpload.classList.add('upload--open')
for (let i = 0, max = getFormInfo.length; i < max; i++) {
getFormInfo[i].style.display = 'block'
}
}
2 changes: 2 additions & 0 deletions src/open_inwoner/js/components/upload-document/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import './show-file-info'
import './file-input-errors'
91 changes: 91 additions & 0 deletions src/open_inwoner/js/components/upload-document/show-file-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const fileUploadInput = document.getElementById('id_file')
const sizeInfo = document.getElementById('uploadSize')
const nameInfo = document.getElementById('uploadName')
const closeButton = document.getElementById('closeUpload')
const submitUpload = document.getElementById('submitUpload')
// show info
const formControlInfo = document.querySelectorAll('.form__control--info')

if (fileUploadInput) {
// Convert the file size to a readable format
const formatFileSize = function (bytes) {
const suffixes = ['B', 'kB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(1024))
return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${suffixes[i]}`
}
// initial values
submitUpload.style.cssText = `
opacity: 0.5;
filter: grayscale(100%);
cursor: default;
`
sizeInfo.style.display = 'none'
nameInfo.style.display = 'none'
for (let i = 0, max = formControlInfo.length; i < max; i++) {
formControlInfo[i].style.display = 'none'
}

fileUploadInput.addEventListener('change', function (e) {
const files = e.target.files

if ((files.length === 0) | (files === null) | (files === undefined)) {
submitUpload.style.cssText = `
opacity: 0.5;
filter: grayscale(100%);
cursor: default;
`
// Hide the size element if user doesn't choose any file
sizeInfo.style.display = 'none'
nameInfo.style.display = 'none'
for (let i = 0, max = formControlInfo.length; i < max; i++) {
formControlInfo[i].style.display = 'none'
}
} else {
submitUpload.style.cssText = `
opacity: 1;
filter: none;
cursor: pointer;
`
// Display info
sizeInfo.textContent = formatFileSize(files[0].size)
nameInfo.textContent = `${files[0].name}`
// Display in DOM
sizeInfo.style.display = 'inline-block'
nameInfo.style.display = 'inline-block'
for (let i = 0, max = formControlInfo.length; i < max; i++) {
formControlInfo[i].style.display = 'block'
}
}
})

if (closeButton) {
closeButton.addEventListener('click', (event) => {
submitUpload.style.cssText = `
opacity: 0.5;
filter: grayscale(100%);
cursor: default;
`
for (let i = 0, max = formControlInfo.length; i < max; i++) {
formControlInfo[i].style.display = 'none'
}
})
}

// if there is only 1 case-type, remove select and its surrounding label
document
.querySelectorAll('.file-type__select')
.forEach(function (selectType) {
console.log(selectType)
if (selectType.querySelector('input[type="hidden"]')) {
selectType.style.display = 'none'
}
})

// Firefox focus bug fix
fileUploadInput.addEventListener('focus', function () {
fileUploadInput.classList.add('has-focus')
})
fileUploadInput.addEventListener('blur', function () {
fileUploadInput.classList.remove('has-focus')
})
}
180 changes: 180 additions & 0 deletions src/open_inwoner/scss/components/Form/DocumentUpload.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,188 @@
#document-upload {
gap: var(--spacing-tiny);

.button[type='submit']:disabled {
background-color: var(--color-gray) !important;
border-color: var(--color-gray) !important;
color: var(--color-gray-light);
pointer-events: none;
cursor: default;
}

.form__control.upload .form__submit {
*[class*='icon'],
.button {
position: initial;
margin-top: 2em;
}
}

input[type='text'] {
max-width: var(--mobile-xs-width);
}

.inputfile-group {
display: block;

.label,
.close {
display: block;
}
}
}

/// File-input site wide
input[type='file'] {
background-color: var(--color-white);
color: var(--color-primary-lighter);
border: 1px solid var(--color-mute);
border-radius: var(--border-radius);
display: flex;
flex-direction: column;
min-width: var(--mobile-xs-width);
max-width: 500px;
padding: 0;
overflow: hidden;
cursor: pointer;
}

/// File-input button site wide
input[type='file']::file-selector-button {
color: var(--color-white);
background-color: var(--color-primary);
text-transform: uppercase;
border: 1px;
border-radius: var(--border-radius);
font-size: var(--font-size-body);
line-height: var(--font-line-height-body);
height: var(--row-height);
font-weight: normal;
text-align: center;
vertical-align: middle;
cursor: pointer;
white-space: nowrap;
padding: 0 12px 0 12px;
margin: 0 12px 0 0;
width: 200px;
}

.button-row .upload-button--disabled {
background-color: var(--color-gray) !important;
border-color: var(--color-gray) !important;
}

.form__open-upload {
.file-type__select {
max-width: var(--mobile-xs-width);
}
.form__control > .label *[class*='icon'] {
top: 69%;
}

.input-file {
position: relative;
max-width: var(--mobile-xs-width);

*[class*='icons'] {
position: absolute;
top: 18px;
left: 12px;
color: orange;
}

/// Hidden file-input for cases
.inputfile {
display: inline-block;
margin-top: var(--spacing-large);
width: var(--mobile-xs-width);
height: var(--row-height);
opacity: 0;
overflow: hidden;
z-index: 200;
}

.inputfile + label {
display: inline-block;
position: absolute;
top: -6px;
left: 0;
padding: var(--spacing-medium) var(--spacing-large) var(--spacing-medium)
calc(2 * (var(--spacing-extra-large)));
font-size: var(--font-size-body);
color: var(--color-font-primary);
background-color: var(--color-primary);
border: 1px solid var(--color-primary);
border-radius: var(--border-radius);
width: 200px;
z-index: -1;
}

.inputfile:focus + label,
.inputfile.has-focus + label,
.inputfile:hover + label,
.inputfile + label:hover {
background-color: var(--color-primary-darker);
top: -5px;
transition: all 0.3s, background-color 0.3s;
}

.inputfile + label *[class*='icons'] {
width: 1.3em;
height: 1em;
vertical-align: middle;
color: white;
margin-top: -0.15em;
}

.inputfile + label {
cursor: pointer; /* "hand" cursor */
}

.inputfile:focus + label {
outline: 2px solid orange;
outline: -webkit-focus-ring-color auto 5px;
}
}

.close .button--transparent {
color: var(--color-red);
}

.info-container {
display: none;
}

.fieldset-container {
display: flex;
box-sizing: border-box;
flex-direction: row;
justify-content: space-around;
border: 1px solid lightgray;
border-radius: 4px;
max-width: var(--mobile-xs-width);
height: 80px;
padding-top: var(--spacing-large);
margin-bottom: 20px;

.fieldset__content {
color: var(--color-mute);
width: 200px;

.upload-info {
display: inline-block;
font-family: var(--font-family-body);
font-size: var(--font-size-body);
color: var(--color-mute);
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

&__name {
color: var(--font-color-body);
font-weight: bold;
}
}
}
}
}
8 changes: 8 additions & 0 deletions src/open_inwoner/scss/components/Form/Form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@
}
}
}
&__control
.label
.notifications__errors
.notification--warning
*[class*='icon'] {
position: static;
transform: translateY(-5px);
}

&__control > .label .p:last-child {
font-size: var(--font-size-body-small);
Expand Down
Loading

0 comments on commit 204d608

Please sign in to comment.