Skip to content

Commit a9bdb82

Browse files
committed
Custom inputs
1 parent d48d7fd commit a9bdb82

36 files changed

+3246
-2
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "2.0",
2+
"version": "3.0",
33
"name": "laravel/laravel",
44
"type": "project",
55
"description": "The skeleton application for the Laravel framework.",

resources/css/app.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ iframe {
124124
background: var(--scrollbar-thumb);
125125
}
126126

127-
#app, .section {
127+
#app {
128128
float: left;
129129
width: 100%;
130130
position: relative;
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<script setup>
2+
import axios from 'axios'
3+
import Input from '@/components/input/Input.vue'
4+
import avatar_default from './profil/avatar.png'
5+
import { toRefs, ref } from 'vue'
6+
7+
const props = defineProps({
8+
avatar: { default: avatar_default },
9+
label: { default: 'Select image' },
10+
remove_avatar_url: { default: '/web/api/remove/avatar' },
11+
remove_success: { default: 'Avatar removed.' },
12+
remove_error: { default: 'Avatar not removed.' },
13+
})
14+
15+
const avatar_path = ref(null)
16+
17+
if (props.avatar) {
18+
avatar_path.value = '/storage/' + props.avatar
19+
20+
if (props.avatar.toLowerCase().startsWith('http://')) {
21+
avatar_path.value = props.avatar
22+
}
23+
24+
if (props.avatar.toLowerCase().startsWith('https://')) {
25+
avatar_path.value = props.avatar
26+
}
27+
} else {
28+
avatar_path.value = avatar_default
29+
}
30+
31+
function getImagePath(e) {
32+
const path = URL.createObjectURL(e.target.files[0])
33+
if (path) {
34+
avatar_path.value = path
35+
}
36+
}
37+
38+
async function removeAvatar() {
39+
try {
40+
await axios.post(props.remove_avatar_url, [])
41+
avatar_path.value = avatar_default
42+
alert(props.remove_success)
43+
} catch (err) {
44+
alert(props.remove_error)
45+
}
46+
}
47+
</script>
48+
49+
<template>
50+
<div class="input-group">
51+
<div class="avatar-input">
52+
<div @click="removeAvatar" class="delete-avatar" :title="$t('Remove avatar')">
53+
<svg width="24px" height="24px" viewBox="0 0 24.75 24.75">
54+
<path
55+
d="M9.87787 4.24993C10.1871 3.37503 11.0215 2.75 12 2.75C12.9785 2.75 13.813 3.37503 14.1222 4.24993C14.2602 4.64047 14.6887 4.84517 15.0793 4.70713C15.4698 4.56909 15.6745 4.1406 15.5365 3.75007C15.022 2.29459 13.634 1.25 12 1.25C10.3661 1.25 8.97804 2.29459 8.46361 3.75007C8.32557 4.1406 8.53026 4.56909 8.9208 4.70713C9.31134 4.84517 9.73983 4.64047 9.87787 4.24993Z" />
56+
<path d="M2.75 6C2.75 5.58579 3.08579 5.25 3.5 5.25H20.5001C20.9143 5.25 21.2501 5.58579 21.2501 6C21.2501 6.41421 20.9143 6.75 20.5001 6.75H3.5C3.08579 6.75 2.75 6.41421 2.75 6Z" />
57+
<path
58+
d="M5.11686 7.75166C5.53015 7.72411 5.88753 8.03681 5.91508 8.45011L6.37503 15.3492C6.46488 16.6971 6.52891 17.6349 6.66948 18.3405C6.80583 19.025 6.99616 19.3873 7.26957 19.6431C7.54299 19.8988 7.91715 20.0647 8.60915 20.1552C9.32255 20.2485 10.2626 20.25 11.6134 20.25H12.3868C13.7376 20.25 14.6776 20.2485 15.391 20.1552C16.083 20.0647 16.4572 19.8988 16.7306 19.6431C17.004 19.3873 17.1943 19.025 17.3307 18.3405C17.4712 17.6349 17.5353 16.6971 17.6251 15.3492L18.0851 8.45011C18.1126 8.03681 18.47 7.72411 18.8833 7.75166C19.2966 7.77921 19.6093 8.13659 19.5818 8.54989L19.1183 15.5016C19.0328 16.7844 18.9637 17.8205 18.8018 18.6336C18.6334 19.4789 18.347 20.185 17.7554 20.7384C17.1638 21.2919 16.4402 21.5307 15.5856 21.6425C14.7635 21.75 13.7251 21.75 12.4395 21.75H11.5607C10.2751 21.75 9.23663 21.75 8.41459 21.6425C7.55994 21.5307 6.83639 21.2919 6.2448 20.7384C5.6532 20.185 5.36678 19.4789 5.19838 18.6336C5.03641 17.8205 4.96735 16.7844 4.88186 15.5016L4.41841 8.54989C4.39085 8.13659 4.70356 7.77921 5.11686 7.75166Z" />
59+
</svg>
60+
</div>
61+
62+
<img :src="avatar_path" class="avatar-image" />
63+
64+
<Input @change="getImagePath" :label="props.label" name="avatar" type="file" />
65+
</div>
66+
</div>
67+
</template>
68+
69+
<style scoped>
70+
.avatar-input {
71+
position: relative;
72+
display: flex;
73+
float: left;
74+
width: 100%;
75+
}
76+
.delete-avatar {
77+
position: absolute;
78+
top: 60px;
79+
left: 60px;
80+
width: 30px;
81+
height: 30px;
82+
padding: 3px;
83+
border-radius: 50%;
84+
cursor: pointer;
85+
color: #fff;
86+
border: 2px solid var(--wow-bg);
87+
background: var(--wow-accent);
88+
}
89+
.delete-avatar svg {
90+
width: 20px;
91+
height: 20px;
92+
fill: #fff;
93+
}
94+
.delete-avatar:hover {
95+
background: #f23;
96+
}
97+
.avatar-image {
98+
float: left;
99+
min-width: 80px;
100+
max-width: 80px;
101+
min-height: 80px;
102+
max-height: 80px;
103+
padding: 3px;
104+
margin-right: 20px;
105+
margin-top: 10px;
106+
border-radius: 50%;
107+
object-fit: cover;
108+
border: 2px solid var(--wow-accent);
109+
}
110+
</style>
111+
112+
<!-- Avatars https://i.pravatar.cc/128 -->
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script setup>
2+
let props = defineProps(['color', 'text'])
3+
</script>
4+
5+
<template>
6+
<span class="color">{{ text }}</span>
7+
</template>
8+
9+
<style>
10+
.color {
11+
color: v-bind('props.color') !important;
12+
}
13+
</style>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script setup>
2+
let props = defineProps(['text', 'class'])
3+
</script>
4+
5+
<template>
6+
<button :class="props?.class">{{ props?.text ?? 'Submit' }}</button>
7+
</template>
8+
9+
<style>
10+
button {
11+
float: right;
12+
margin-top: 20px;
13+
background: var(--wow-accent);
14+
border-radius: var(--wow-border-radius);
15+
font-size: var(--wow-font-size) !important;
16+
padding: var(--wow-font-size) calc(var(--wow-font-size) * 3) !important;
17+
border-radius: calc(var(--wow-font-size) / 2);
18+
border: 1px solid var(--wow-accent);
19+
font-weight: 600 !important;
20+
color: #fff;
21+
cursor: pointer;
22+
transition: all 0.6s;
23+
}
24+
25+
button:hover {
26+
filter: brightness(1.3);
27+
}
28+
</style>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<template>
2+
<div class="input-group">
3+
<div class="checkbox-line">
4+
<input class="checkbox" type="checkbox" :value="props.value" :name="props.name" v-model="props.modelValue" @change="emits('update:modelValue', props.modelValue)" />
5+
<div class="checkmark">
6+
<IconCheckmark v-if="checked" />
7+
</div>
8+
<label v-if="props.label" :for="props.name">{{ props.label }} <slot></slot></label>
9+
</div>
10+
</div>
11+
</template>
12+
13+
<script setup>
14+
import { computed } from 'vue'
15+
import IconCheckmark from './icons/IconCheckmark.vue'
16+
17+
const emits = defineEmits(['update:modelValue', 'change'])
18+
const props = defineProps({
19+
name: { type: String },
20+
modelValue: { type: [Array, Boolean] },
21+
value: { type: String, required: true },
22+
label: { type: String, required: true },
23+
})
24+
25+
const checked = computed(() => {
26+
if (props.modelValue instanceof Array) {
27+
return props.modelValue.includes(props.value)
28+
}
29+
return props.modelValue
30+
})
31+
</script>
32+
33+
<style>
34+
@import './css/input-root.css';
35+
</style>
36+
37+
<style scoped>
38+
@import './css/input.css';
39+
</style>
40+
41+
<!--
42+
43+
// Multiple Array with strings values
44+
let money = ref(['card','cash']) // Default selected in array
45+
46+
<Checkbox label="Cash" value="cash" v-model="money" name="pay_cash" />
47+
<Checkbox label="Card" value="card" v-model="money" name="pay_card" />
48+
49+
// Single (true|false)
50+
let remember_me = ref(true)
51+
52+
<Checkbox label="Remember me 1" value="1" v-model="remember_me" name="remember_me" />
53+
54+
-->
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<template>
2+
<div class="input-group">
3+
<div class="checkbox-line">
4+
<label v-if="props.label" :for="props.name">{{ props.label }} <slot></slot></label>
5+
<input class="checkbox checkbox-checkmark-onoff" type="checkbox" :value="props.value" :name="props.name" v-model="props.modelValue" @change="emits('update:modelValue', props.modelValue)" />
6+
<div :class="{ 'checkmark-onoff': true, 'checkmark-onoff-checked': checked }">
7+
<div class="dot"></div>
8+
</div>
9+
</div>
10+
</div>
11+
</template>
12+
13+
<script setup>
14+
import { computed } from 'vue'
15+
16+
const emits = defineEmits(['update:modelValue', 'change'])
17+
const props = defineProps({
18+
name: { type: String },
19+
modelValue: { type: [Array, Boolean] },
20+
value: { type: String, required: true },
21+
label: { type: String, required: true },
22+
})
23+
24+
const checked = computed(() => {
25+
if (props.modelValue instanceof Array) {
26+
return props.modelValue.includes(props.value)
27+
}
28+
return props.modelValue
29+
})
30+
</script>
31+
32+
<style>
33+
@import './css/input-root.css';
34+
</style>
35+
36+
<style scoped>
37+
@import './css/input.css';
38+
</style>
39+
40+
<!--
41+
42+
let lights = ref(true)
43+
44+
<CheckboxOnOff label="Enable lights" value="1" v-model="lights" name="lights" />
45+
46+
-->
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<template>
2+
<div class="input-group">
3+
<label v-if="props.label" :for="props.name">{{ props.label }} <slot></slot></label>
4+
<input
5+
ref="input"
6+
:type="props.type"
7+
:name="props.name"
8+
v-model="props.modelValue"
9+
:class="props.class"
10+
:placeholder="props.placeholder"
11+
@input="emits('update:modelValue', $event.target.value)"
12+
@keydown="emits('keydown', $event)"
13+
@keyup="emits('keyup', $event)"
14+
@change="emits('change', $event)" />
15+
</div>
16+
</template>
17+
18+
<script setup>
19+
import { ref, onMounted } from 'vue'
20+
21+
const emits = defineEmits(['update:modelValue', 'keydown', 'keyup', 'change'])
22+
const props = defineProps({
23+
modelValue: [String, Number],
24+
name: { type: String },
25+
label: { type: String },
26+
placeholder: { type: String },
27+
class: { type: [String, Array] },
28+
type: {
29+
type: String,
30+
default: 'text',
31+
required: true,
32+
},
33+
focus: false,
34+
})
35+
36+
let input = ref(null)
37+
38+
onMounted(() => {
39+
if (props.focus) {
40+
input.value.focus()
41+
}
42+
})
43+
</script>
44+
45+
<style>
46+
@import './css/input-root.css';
47+
</style>
48+
49+
<style scoped>
50+
@import './css/input.css';
51+
</style>
52+
53+
<!--
54+
import Input from '@/components/form/Input.vue'
55+
56+
let value = 'Maxiu'
57+
58+
<Input type="text" name="name" v-model="value" />
59+
-->

0 commit comments

Comments
 (0)