Merge branch 'main' into states
# Conflicts: # app/Domain/CalendarGenerator.php # app/Domain/VacationRequestStateManager.php # app/Eloquent/Models/VacationRequest.php # app/Eloquent/Observers/VacationRequestObserver.php # composer.json # composer.lock # tests/Feature/VacationRequestTest.php
This commit is contained in:
12
resources/js/Composables/yearPeriodInfo.js
Normal file
12
resources/js/Composables/yearPeriodInfo.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import {computed} from 'vue'
|
||||
import {usePage} from '@inertiajs/inertia-vue3'
|
||||
|
||||
export default function useCurrentYearPeriodInfo() {
|
||||
const minDate = computed(() => new Date(usePage().props.value.years.current, 0, 1))
|
||||
const maxDate = computed(() => new Date(usePage().props.value.years.current, 11, 31))
|
||||
|
||||
return {
|
||||
minDate,
|
||||
maxDate,
|
||||
}
|
||||
}
|
@@ -1,10 +1,20 @@
|
||||
<template>
|
||||
<InertiaHead title="Kalendarz urlopów" />
|
||||
<div class="bg-white shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Kalendarz urlopów
|
||||
</h2>
|
||||
<div class="flex justify-between items-center p-4 sm:px-6">
|
||||
<div>
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Kalendarz urlopów
|
||||
</h2>
|
||||
</div>
|
||||
<div>
|
||||
<a
|
||||
:href="`/timesheet/${selectedMonth.value}`"
|
||||
class="inline-flex items-center px-4 py-3 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Pobierz plik excel
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-center table-fixed text-sm border border-gray-300">
|
||||
@@ -19,7 +29,7 @@
|
||||
<MenuButton
|
||||
class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
|
||||
>
|
||||
{{ selectedMonth.name }}
|
||||
{{ selectedMonth.name }} {{ years.current }}
|
||||
<ChevronDownIcon class="-mr-1 ml-2 h-5 w-5" />
|
||||
</MenuButton>
|
||||
</div>
|
||||
@@ -42,8 +52,7 @@
|
||||
v-slot="{ active }"
|
||||
>
|
||||
<InertiaLink
|
||||
href="/vacation-calendar"
|
||||
:data="{ month: month.value }"
|
||||
:href="`/vacation-calendar/${month.value}`"
|
||||
:class="[active ? 'bg-gray-100 text-gray-900' : 'text-gray-700', 'flex w-full font-normal px-4 py-2 text-sm']"
|
||||
>
|
||||
{{ month.name }}
|
||||
@@ -151,6 +160,10 @@ export default {
|
||||
type: String,
|
||||
default: () => 'january',
|
||||
},
|
||||
years: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const {getMonths, findMonth} = useMonthInfo()
|
||||
|
@@ -48,6 +48,7 @@
|
||||
id="date"
|
||||
v-model="form.date"
|
||||
placeholder="Wybierz datę"
|
||||
:config="{minDate, maxDate}"
|
||||
class="block w-full max-w-lg shadow-sm rounded-md sm:text-sm"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.date, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.date }"
|
||||
/>
|
||||
@@ -81,8 +82,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import {useForm} from '@inertiajs/inertia-vue3'
|
||||
import FlatPickr from 'vue-flatpickr-component'
|
||||
import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo'
|
||||
|
||||
export default {
|
||||
name: 'HolidayCreate',
|
||||
@@ -95,7 +97,13 @@ export default {
|
||||
date: null,
|
||||
})
|
||||
|
||||
return { form }
|
||||
const {minDate, maxDate} = useCurrentYearPeriodInfo()
|
||||
|
||||
return {
|
||||
form,
|
||||
minDate,
|
||||
maxDate,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createHoliday() {
|
||||
|
@@ -28,6 +28,76 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Listbox
|
||||
v-model="form.user"
|
||||
as="div"
|
||||
class="sm:grid sm:grid-cols-3 py-4 items-center"
|
||||
>
|
||||
<ListboxLabel class="block text-sm font-medium text-gray-700">
|
||||
Osoba składająca wniosek
|
||||
</ListboxLabel>
|
||||
<div class="mt-1 relative sm:mt-0 sm:col-span-2">
|
||||
<ListboxButton
|
||||
class="bg-white relative w-full max-w-lg border rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default sm:text-sm focus:ring-1"
|
||||
:class="{ 'border-red-300 text-red-900 focus:outline-none focus:ring-red-500 focus:border-red-500': form.errors.type, 'focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300': !form.errors.type }"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<img
|
||||
:src="form.user.avatar"
|
||||
class="flex-shrink-0 h-6 w-6 rounded-full"
|
||||
>
|
||||
<span class="ml-3 block truncate">{{ form.user.name }}</span>
|
||||
</span>
|
||||
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||
<SelectorIcon class="h-5 w-5 text-gray-400" />
|
||||
</span>
|
||||
</ListboxButton>
|
||||
|
||||
<transition
|
||||
leave-active-class="transition ease-in duration-100"
|
||||
leave-from-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<ListboxOptions
|
||||
class="absolute z-10 mt-1 w-full max-w-lg bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
|
||||
>
|
||||
<ListboxOption
|
||||
v-for="user in users.data"
|
||||
:key="user.id"
|
||||
v-slot="{ active, selected }"
|
||||
as="template"
|
||||
:value="user"
|
||||
>
|
||||
<li :class="[active ? 'text-white bg-blumilk-600' : 'text-gray-900', 'cursor-default select-none relative py-2 pl-3 pr-9']">
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
:src="user.avatar"
|
||||
alt=""
|
||||
class="flex-shrink-0 h-6 w-6 rounded-full"
|
||||
>
|
||||
<span :class="[selected ? 'font-semibold' : 'font-normal', 'ml-3 block truncate']">
|
||||
{{ user.name }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
v-if="selected"
|
||||
:class="[active ? 'text-white' : 'text-blumilk-600', 'absolute inset-y-0 right-0 flex items-center pr-4']"
|
||||
>
|
||||
<CheckIcon class="h-5 w-5" />
|
||||
</span>
|
||||
</li>
|
||||
</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</transition>
|
||||
<p
|
||||
v-if="form.errors.type"
|
||||
class="mt-2 text-sm text-red-600"
|
||||
>
|
||||
{{ form.errors.type }}
|
||||
</p>
|
||||
</div>
|
||||
</Listbox>
|
||||
<Listbox
|
||||
v-model="form.type"
|
||||
as="div"
|
||||
@@ -161,6 +231,25 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 py-4 items-center">
|
||||
<label
|
||||
for="flowSkipped"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Natychmiastowo zatwierdź wniosek
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<Switch
|
||||
id="flowSkipped"
|
||||
v-model="form.flowSkipped"
|
||||
:class="[form.flowSkipped ? 'bg-blumilk-500' : 'bg-gray-200', 'relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500']"
|
||||
>
|
||||
<span
|
||||
:class="[form.flowSkipped ? 'translate-x-5' : 'translate-x-0', 'pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200']"
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end py-3">
|
||||
<div class="space-x-3">
|
||||
<InertiaLink
|
||||
@@ -183,16 +272,18 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {useForm, usePage} from '@inertiajs/inertia-vue3'
|
||||
import {useForm} from '@inertiajs/inertia-vue3'
|
||||
import FlatPickr from 'vue-flatpickr-component'
|
||||
import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions} from '@headlessui/vue'
|
||||
import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions, Switch} from '@headlessui/vue'
|
||||
import {CheckIcon, SelectorIcon, XCircleIcon} from '@heroicons/vue/solid'
|
||||
import {reactive, ref, computed} from 'vue'
|
||||
import {reactive, ref} from 'vue'
|
||||
import axios from 'axios'
|
||||
import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestCreate',
|
||||
components: {
|
||||
Switch,
|
||||
FlatPickr,
|
||||
Listbox,
|
||||
ListboxButton,
|
||||
@@ -204,6 +295,14 @@ export default {
|
||||
XCircleIcon,
|
||||
},
|
||||
props: {
|
||||
auth: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
users: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
vacationTypes: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
@@ -215,15 +314,16 @@ export default {
|
||||
},
|
||||
setup(props) {
|
||||
const form = useForm({
|
||||
user: props.users.data.find(user => user.id === props.auth.user.id),
|
||||
from: null,
|
||||
to: null,
|
||||
type: props.vacationTypes[0],
|
||||
comment: null,
|
||||
flowSkipped: false,
|
||||
})
|
||||
|
||||
const estimatedDays = ref([])
|
||||
const minDate = computed(() => new Date(usePage().props.value.years.current, 0, 1))
|
||||
const maxDate = computed(() => new Date(usePage().props.value.years.current, 11, 31))
|
||||
const {minDate, maxDate} = useCurrentYearPeriodInfo()
|
||||
|
||||
const disableDates = [
|
||||
date => (date.getDay() === 0 || date.getDay() === 6),
|
||||
@@ -254,6 +354,7 @@ export default {
|
||||
.transform(data => ({
|
||||
...data,
|
||||
type: data.type.value,
|
||||
user: data.user.id,
|
||||
}))
|
||||
.post('/vacation-requests')
|
||||
},
|
||||
|
@@ -390,4 +390,4 @@ export default {
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
@@ -42,7 +42,35 @@
|
||||
"Vacation limits have been updated.": "Limity urlopów zostały zaktualizowane.",
|
||||
"Vacation request has been created.": "Wniosek urlopowy został utworzony.",
|
||||
"Vacation request has been accepted.": "Wniosek urlopowy został zaakceptowany.",
|
||||
"Vacation request has been approved.": "Wniosek urlopowy został zatwierdzony.",
|
||||
"Vacation request has been rejected.": "Wniosek urlopowy został odrzucony.",
|
||||
"Vacation request has been cancelled.": "Wniosek urlopowy został anulowany."
|
||||
|
||||
"Vacation request has been cancelled.": "Wniosek urlopowy został anulowany.",
|
||||
"Sum:": "Suma:",
|
||||
"Date": "Data",
|
||||
"Day of week": "Dzień tygodnia",
|
||||
"Start date": "Data rozpoczęcia",
|
||||
"End date": "Data zakończenia",
|
||||
"Worked hours": "Liczba godzin",
|
||||
"Hi :user!": "Cześć :user!",
|
||||
"The vacation request :title has changed state to :state.": "Wniosek urlopowy :title zmienił status na :state.",
|
||||
"Vacation request :title": "Wniosek urlopowy :title",
|
||||
"Regards": "Z poważaniem",
|
||||
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "Jeżeli masz problemy z kliknięciem przycisku \":actionText\", skopiuj i wklej poniższy adres w pasek przeglądarki:",
|
||||
"All rights reserved.": "Wszelkie prawa zastrzeżone",
|
||||
"Show vacation request": "Pokaż wniosek",
|
||||
"Vacation request :title has been created" : "Wniosek :title został utworzony",
|
||||
"The vacation request :title has been created correctly in the :appName.": "W systemie :appName został poprawnie utworzony wniosek urlopowy :title.",
|
||||
"Vacation type: :type": "Rodzaj wniosku: :type",
|
||||
"From :from to :to (number of days: :days)": "Od :from do :to (liczba dni: :days)",
|
||||
"Click here for details": "Kliknij, aby zobaczyć szczegóły",
|
||||
"Vacation request :title is waiting for your approval": "Wniosek urlopowy :title czeka na zaakceptowanie",
|
||||
"The vacation request :title from user: :requester is waiting for your approval.": "Wniosek urlopowy :title od użytkownika :requester czeka na Twoją akceptację.",
|
||||
"Vacation request :title has been approved": "Wniosek urlopowy :title został zatwierdzony",
|
||||
"The vacation request :title for user :requester has been approved.": "Wniosek urlopowy :title od użytkownika :requester został zatwierdzony.",
|
||||
"Vacation request :title has been cancelled": "Wniosek urlopowy :title został anulowany",
|
||||
"The vacation request :title for user :requester has been cancelled.": "Wniosek urlopowy :title od użytkownika :requester został anulowany.",
|
||||
"Vacation request :title has been rejected": "Wniosek urlopowy :title został odrzucony",
|
||||
"The vacation request :title for user :requester has been rejected.": "Wniosek urlopowy :title od użytkownika :requester został odrzucony.",
|
||||
"Vacation request :title has been created on your behalf": "Wniosek urlopowy :title został utworzony w Twoim imieniu",
|
||||
"The vacation request :title has been created correctly by user :creator on your behalf in the :appName.": "W systemie :appName został poprawnie utworzony wniosek urlopowy :title w Twoim imieniu przez użytkownika :creator."
|
||||
}
|
||||
|
286
resources/views/vendor/mail/html/themes/mail.css
vendored
Normal file
286
resources/views/vendor/mail/html/themes/mail.css
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
/* Base */
|
||||
|
||||
body, body *:not(html):not(style):not(br):not(tr):not(code) {
|
||||
font-family: Avenir, Helvetica, sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f5f8fa;
|
||||
color: #74787e;
|
||||
height: 100%;
|
||||
hyphens: auto;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
-moz-hyphens: auto;
|
||||
-ms-word-break: break-all;
|
||||
width: 100% !important;
|
||||
-webkit-hyphens: auto;
|
||||
-webkit-text-size-adjust: none;
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
blockquote {
|
||||
line-height: 1.4;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3c5f97;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
|
||||
h1 {
|
||||
color: #2F3133;
|
||||
font-size: 19px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #2F3133;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #2F3133;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #74787e;
|
||||
font-size: 16px;
|
||||
line-height: 1.5em;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p.sub {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
|
||||
.wrapper {
|
||||
background-color: #f5f8fa;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
.header {
|
||||
padding: 25px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header a {
|
||||
color: #3c5f97;
|
||||
font-size: 19px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px 0 #ffffff;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
|
||||
.body {
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #edeff2;
|
||||
border-top: 1px solid #edeff2;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
}
|
||||
|
||||
.inner-body {
|
||||
background-color: #ffffff;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 570px;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 570px;
|
||||
}
|
||||
|
||||
/* Subcopy */
|
||||
|
||||
.subcopy {
|
||||
border-top: 1px solid #edeff2;
|
||||
margin-top: 25px;
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
.subcopy p {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
.footer {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
width: 570px;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 570px;
|
||||
}
|
||||
|
||||
.footer p {
|
||||
color: #aeaeae;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
|
||||
.table table {
|
||||
margin: 30px auto;
|
||||
width: 100%;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
}
|
||||
|
||||
.table th {
|
||||
color: #74787e;
|
||||
border-bottom: 1px solid #edeff2;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.table td {
|
||||
color: #74787e;
|
||||
font-size: 15px;
|
||||
line-height: 18px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.content-cell {
|
||||
padding: 35px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.action {
|
||||
margin: 30px auto;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.button-blue, .button-primary {
|
||||
background-color: #3c5f97;
|
||||
border-top: 10px solid #3c5f97;
|
||||
border-right: 18px solid #3c5f97;
|
||||
border-bottom: 10px solid #3c5f97;
|
||||
border-left: 18px solid #3c5f97;
|
||||
}
|
||||
|
||||
.button-green, .button-success {
|
||||
background-color: #22c55e;
|
||||
border-top: 10px solid #22c55e;
|
||||
border-right: 18px solid #22c55e;
|
||||
border-bottom: 10px solid #22c55e;
|
||||
border-left: 18px solid #22c55e;
|
||||
}
|
||||
|
||||
.button-red, .button-error {
|
||||
background-color: #ef4444;
|
||||
border-top: 10px solid #ef4444;
|
||||
border-right: 18px solid #ef4444;
|
||||
border-bottom: 10px solid #ef4444;
|
||||
border-left: 18px solid #ef4444;
|
||||
}
|
||||
|
||||
/* Panels */
|
||||
|
||||
.panel {
|
||||
margin: 0 0 21px;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
background-color: #edeff2;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.panel-item {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.panel-item p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* Promotions */
|
||||
|
||||
.promotion {
|
||||
background-color: #FFFFFF;
|
||||
border: 2px dashed #9BA2AB;
|
||||
margin: 0;
|
||||
margin-bottom: 25px;
|
||||
margin-top: 25px;
|
||||
padding: 24px;
|
||||
width: 100%;
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
}
|
||||
|
||||
.promotion h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.promotion p {
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
Reference in New Issue
Block a user