Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form Uniformity #212

Merged
merged 14 commits into from
Jul 14, 2023
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,42 @@ The default newsletter template is:

Take a look at existing articles for the various classes and where they're used.

### Forms

Among templates, there are a separate group of templates which use the `_form.njk` template as a base. These templates have a slightly different pattern and some more features.

```jinja
{% extends '_base.njk' %}
{% import '_form.njk' as forms %}

{% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %}

{% block pagecontent %}
{% call forms.form() %}
{# Form Content #}
{% endcall %}
{% endblock %}

{% block customcss %}
{{ forms.formCss() }}
<style>
{# Extra Styles #}
</style>
{% endblock %}

{% block customjs %}
{{ forms.formFunction() }}
<script>
axios.defaults.withCredentials = true;
axios.defaults.headers.common['X-CSRF-TOKEN'] = '{{ csrfToken }}';

{# Other Functions #}
</script>
{% endblock %}
```

For in-depth info about the same, check out the [forms](https://github.com/kgpmask/MASK/docs/Forms.md) markdown file.

---

## Routers
Expand Down
167 changes: 167 additions & 0 deletions assets/styles/form.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
.message {
position: absolute;
top: 0;
right: calc(50vw - 220px);
padding: 20px;
z-index: 100;
color: #fff;
font-weight: 600;
font-size: 18px;
width: 400px;
transform-origin: top;
transition: transform 0.3s ease;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
.error {
background-color: rgba(255, 51, 51, 0.85);
}
.success {
background-color: rgba(75, 189, 67, 0.85);
}
.hidden {
transform: scaleY(0);
}
.form-container{
padding: 23px 25px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transform: 0.3s;
}
form {
display: flex;
flex-direction: column;
border: 1px solid var(--off-white);
border-radius: 12px;
padding: 12px 10px;
width: 40%;
background-color: rgba(255,255,255,0.13);
backdrop-filter: blur(5px);
}
form * {
outline: none;
border: none;
}
button {
align-self: center;
margin: 20px;
width: 44%;
background-color: var(--red);
color: white;
padding: 12px 0;
font-size: 18px;
font-weight: 600;
border-radius: 12px;
cursor: pointer;
}
.item {
display: flex;
flex-direction: column;
text-align: left;
position: relative;
margin: 10px 4vw;
}
.heading {
margin-block-start: 0.83em;
margin-block-end: 0.83em;
}
label {
color: var(--off-white);
margin-inline-start: 0.3em;
margin-block-end: 0.4em;
font-weight: 600;
font-size: 16px;
pointer-events: none;
}
.datetime > label{
top: -7px;
font-size: 16px;
padding: 0 2px;
background-color: rgba(0, 0, 0, 0);
}
input,
select{
background-color: rgba(255,255,255,0.07);
font-weight: 300;
border-radius: 5px;
padding: 10px;
border: 2px solid var(--light-gray);
color: #fff;
outline: none;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
select {
font-weight: 600;
}
.datetime > input {
color-scheme: dark;
}
.option {
position: relative;
display: flex;
align-items: center;
border-radius: 10px;
cursor: pointer;
transition: 0.3s;
padding: 5px 10px;
margin: 7px;
}
.option:focus-within,
.option:hover {
background: hsla(0, 0%, 80%, .14);
}
.option-input {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
z-index: 1;
}
.option-design {
width: 22px;
height: 22px;
border-radius: 100px;
background: linear-gradient(to right bottom, hsl(0deg 100% 75%), hsl(0deg 100% 50%));
position: relative;
}
.checkbox > .option > .option-design {
border-radius: 2px;
}
.option-design::before {
content: '';
display: inline-block;
width: inherit;
height: inherit;
border-radius: inherit;
background: hsl(0, 0%, 90%);
transform: scale(1.1);
transition: 0.3s;
}
.option-input:checked + .option-design::before {
transform: scale(0);
}
.option-text {
color: hsl(0, 0%, 60%);
margin-left: 14px;
font-weight: 900;
transition: 0.3s;
}
.option-input:checked ~ .option-text {
color: hsl(184deg 58% 60%);
}
.singlecheck {
align-self: center;
flex-direction: row-reverse;
}
.singlecheck > .option-text {
margin-right: 14px;
margin-left: unset;
}
select > option {
background-color: var(--darker-gray);
padding: 10px;;
}
177 changes: 177 additions & 0 deletions docs/Forms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Information Regarding Creating Pages Which Has Forms

We are using many pages with forms, to make them uniform



## How to use `_form.njk`

Forms follow the default page template, with a little modification

```jinja
{% extends '_base.njk' %}
{% import '_form.njk' as forms %}

{% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %}

{% block pagecontent %}
{% call forms.form() %}
{# Form Content #}
{% endcall %}
{% endblock %}

{% block customcss %}
{{ forms.formCss() }}
<style>
{# Extra Styles #}
</style>
{% endblock %}

{% block customjs %}
{{ forms.formFunction() }}
<script>
axios.defaults.withCredentials = true;
axios.defaults.headers.common['X-CSRF-TOKEN'] = '{{ csrfToken }}';

{# Other Functions #}
</script>
{% endblock %}
```

Additionally the following variables may be set:

- `pagetitle`: Title of the page (default MASK)
- `pagedesc`: Description of the page (default 'MASK website')
- `thispage`: URL of intended position of current page, used to select active page in NAVBAR (default none)

## Function/Macro Documentation

The following functions/macros are exported from `_form.njk`

- `form(*formheading)` - The main form body, this needs to be executed in a call block. `formheading` is optional.
- `heading(h, label)` - Used to put a heading/divider between items. The arguments are:
- `h` - Heading level (eg, h1, h2, h3).
- `label` - Heading text.
- `field(id, label, *value)` - Text input field. The arguments are:
- `id` - ID of the input tag.
- `label` - Text to display above input tag.
- `value` - Optional, used to give a predefined value to input field.
- `datetime(id, label, value)` - Datetime input field. The arguments are:
- `id` - ID of the input tag.
- `label` - Text to display above input tag.
- `value` - Used to give a predefined value to input field.
- `radio(id, label, options)` or `checkbox(id, label, options)` - Radio/Checkbox buttons. The arguments are:
- `id` - ID of the option container.
- `label` - Text to display above the buttons.
- `options` - Array of options. Its data type is `[ {'id': 'ID of each option', 'label': 'Option text', 'value': 'Option value'}, ... ]`
- `select(id, label, options, *onchange)` - Select tag. The arguments are:
- `id` - ID of the select container.
- `label` - Text to display for the select tag.
- `options` - Array of options. Its data type is `[ {'label': 'Option text', 'value': 'Option value'}, ... ]`
- `onchange` - Optional. Function to call when select option is changed. **The select element will be passed to the function, so it must accept it.**
- `singlecheck(id, label, *checked)` - A single check button, may be used for a True/False value. The arguments are:
- `id` - ID of the check input.
- `label` - Text for the button.
- `checked` - Optional. Determines if option should be checked by default.
- `button(id, label, *onclick)` - Includes buttons in the form. The arguments are:
- `id` - ID of the button.
- `label` - Text displayed on the button
- `onclick` - Optional. The function to be called when the button is pressed. **If not defined, then button will submit the form.**
- `formCss()` - Use this to include the default form styling (present in `assets/styles/form.css`).
- `formFunction()` - Use this to include usefull form functions. The included functions are:
- `getData()` - Extracts data from all the elements made from the above macros, and returns an object with keys as ID's and values as the corresponding values of the ID's.
- `message(response, *location)` - Displays success/error message, and redirects the page to location. Its arguments are:
- `response` - Its the response from the axios post request. It must contain a `message` (the message which is displayed in the pop-up) and a `success` (if its an error or success) attributes.
- `location` - Optional. Location to redirect to. If not defined, then it reloads the page.

## Example Form

Here's an example form with all the elements.

```jinja
{% extends '_base.njk' %}
{% import '_form.njk' as forms %}

{% set scripts = ['https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'] %}

{% set thispage = 'Example Form' %}
{% set pagetitle = 'Example Form' %}

{% block pagecontent %}
{% call forms.form('Example Form') %}
{{ forms.field('name', 'Name') }}
{{ forms.heading('h2', 'Some questions ') }}
{{ forms.checkbox('team', 'Select Teams', [
{
'id':'web',
'label': 'Web Dev',
'value': 'web'
},
{
'id':'quiz',
'label': 'Quiz',
'value': 'quiz'
},
{
'id':'mn',
'label': 'Media And Newsletter',
'value': 'mn'
}]) }}
{{ forms.select('favperson', 'Favourite Person in WebDev', [
{
'label': 'Goos',
'value': 'goos'
},
{
'label': 'Nishkal',
'value': 'np'
},
{
'label': 'Parth',
'value': 'parth'
}], 'change') }}
{{ forms.radio('like', 'DO you like MASK ?', [
{
'id':'yes',
'label': 'YES',
'value': 'yes'
},
{
'id':'no',
'label': 'NO',
'value': 'no'
}]) }}
<div style="display: flex; flex-direction: row; justify-content: space-around; flex-wrap: wrap;">
{{ forms.singlecheck('onichan', 'Onii-Chan', 1) }}
{{ forms.singlecheck('uwu', 'UWU') }}
{{ forms.singlecheck('nyaa', 'nyaaa~~~', 1) }}
</div>
{{ forms.datetime('date', 'Random Date', '2023-07-11') }}
{{ forms.button('submit', 'Submit-nyaa~~', 'print') }}
{% endcall %}
{% endblock %}

{% block customcss %}
{{ forms.formCss() }}
<style>
form {
width: 80%;
}
</style>
{% endblock %}

{% block customjs %}
{{ forms.formFunction() }}
<script>
function change(select) {
console.log('changed');
}
function print() {
console.log(getData());
// const response = (await axios.post)
const response = { message: 'Succesfully Done', success: true }
message(response);
}
</script>
{% endblock %}
```
Loading