🎉 Initial commit
This commit is contained in:
commit
55eebe2603
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="placeholder" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="2">
|
||||
<item index="0" class="java.lang.String" itemvalue="pandas" />
|
||||
<item index="1" class="java.lang.String" itemvalue="PyPDF2" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ReassignedToPlainText" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/html.iml" filepath="$PROJECT_DIR$/.idea/html.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="b737d0e3-1d2f-4475-8572-57c46c9b84d7" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/index.html" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ComposerSettings">
|
||||
<execution />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="JavaScript File" />
|
||||
<option value="CSS File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GitLabServerManager">
|
||||
<selected>-1</selected>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="PhpDebugGeneral" listening_started="true" />
|
||||
<component name="PhpServers">
|
||||
<servers>
|
||||
<server host="localhost" id="1d235f0c-fe6b-4b3e-b325-f93fda89810c" name="localhost" />
|
||||
</servers>
|
||||
</component>
|
||||
<component name="PhpWorkspaceProjectConfiguration" interpreter_name="PHP 7.4" />
|
||||
<component name="ProjectColorInfo">{
|
||||
"customColor": "",
|
||||
"associatedIndex": 8
|
||||
}</component>
|
||||
<component name="ProjectId" id="2MMcvjcsDBvhOAbulzATKjUcXSP" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"git-widget-placeholder": "main",
|
||||
"last_opened_file_path": "/var/www/html/resources/images",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "reference.settings.ide.settings.web.browsers",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/resources/images" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/resources/sounds" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="localhost" type="JavascriptDebugType" uri="http://localhost">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-php-predefined-ba97393d7c68-6f8e3395a2b4-com.jetbrains.php.sharedIndexes-PS-233.14475.35" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="b737d0e3-1d2f-4475-8572-57c46c9b84d7" name="Changes" comment="" />
|
||||
<created>1677581124694</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1677581124694</updated>
|
||||
<workItem from="1677581125789" duration="6392000" />
|
||||
<workItem from="1677601006571" duration="771000" />
|
||||
<workItem from="1677751931686" duration="5887000" />
|
||||
<workItem from="1693601579836" duration="12311000" />
|
||||
<workItem from="1702037752390" duration="651000" />
|
||||
<workItem from="1702145953417" duration="1797000" />
|
||||
<workItem from="1702374711277" duration="607000" />
|
||||
<workItem from="1708611490183" duration="21982000" />
|
||||
<workItem from="1708700627345" duration="5000" />
|
||||
<workItem from="1708700650122" duration="8872000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<watches-manager>
|
||||
<configuration name="JavascriptDebugType">
|
||||
<watch expression=" entr" language="HTML" />
|
||||
</configuration>
|
||||
</watches-manager>
|
||||
</component>
|
||||
<component name="XPathView.XPathProjectComponent">
|
||||
<history />
|
||||
<find-history />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
<select />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 marc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Guest Book
|
||||
|
||||
A small project to train my JavaScript skills.
|
||||
|
||||
This project consists of a simple HTML page with some CSS and JavaScript.
|
||||
|
||||
The user can input a name and a message which will be displayed on the site. The
|
||||
message will be sent to a [ntfy](https://ntfy.sh/) server. Messages will be
|
||||
streamed from the server and displayed immediately on the page.
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<title>Hi!</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/png" href="/resources/images/favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="hi">
|
||||
<h1><span id="rotate">Hi! 🙃</span></h1>
|
||||
</div>
|
||||
|
||||
<div class="guestbook">
|
||||
<h2>Guest Book</h2>
|
||||
<table id="entryTable"></table>
|
||||
</div>
|
||||
|
||||
<div class="guestbook-form">
|
||||
<label for="name"></label>
|
||||
<input type="text" id="name" placeholder="Your name">
|
||||
<label for="entryText"></label>
|
||||
<input type="text" id="entryText" placeholder="Your message...">
|
||||
<button id="submitEntry">Submit</button>
|
||||
</div>
|
||||
<p id="error-message">The name field contains invalid characters.</p>
|
||||
</div>
|
||||
<script src="script.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 530 B |
Binary file not shown.
|
|
@ -0,0 +1,198 @@
|
|||
// Enable debug mode if the URL contains the debug parameter
|
||||
let debug = false;
|
||||
if (window.location.href.includes('debug')) {
|
||||
console.log('Debug mode enabled');
|
||||
debug = true;
|
||||
}
|
||||
|
||||
// Initialize the EventSource and the HTML elements
|
||||
const eventSource = new EventSource('https://ntfy.example.org/guestbook/sse?since=all');
|
||||
const entryText = document.getElementById('entryText');
|
||||
const name = document.getElementById('name');
|
||||
const submitEntry = document.getElementById('submitEntry');
|
||||
const entryTable = document.getElementById('entryTable');
|
||||
const errorMessage = document.getElementById('error-message');
|
||||
const bell = new Audio('/resources/sounds/notification.ogg');
|
||||
|
||||
// Disable the notification sound for the first 2 seconds until the guestbook is loaded initially
|
||||
let bellEnabled = false;
|
||||
|
||||
// Event listener for the Enter key
|
||||
function handleKeydown(event) {
|
||||
if (event.key === 'Enter') {
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the name is valid
|
||||
function checkName(name) {
|
||||
if (name.match(/:\s/)) {
|
||||
errorMessage.classList.add('visible');
|
||||
console.error('Invalid name');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Send new entry to the ntfy server
|
||||
function sendMessage() {
|
||||
const text = entryText.value.trim();
|
||||
const author = name.value.trim() ? name.value.trim() : 'Anonymous';
|
||||
if (checkName(author)) {
|
||||
errorMessage.classList.remove('visible');
|
||||
const message = author + ': ' + text;
|
||||
if (text.length > 0) {
|
||||
fetch('https://ntfy.example.org/guestbook', {
|
||||
method: 'POST',
|
||||
body: message
|
||||
})
|
||||
.then(() => {
|
||||
// Empty the input field
|
||||
entryText.value = '';
|
||||
// Save the name in the local storage
|
||||
localStorage.setItem('name', author);
|
||||
})
|
||||
.catch(error => console.error(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate time passed since the message was sent
|
||||
function timeSince(date) {
|
||||
let seconds = Math.floor(Date.now() / 1000 - date);
|
||||
let interval = Math.floor(seconds / 3600);
|
||||
if (interval >= 2) {
|
||||
return interval + " hours ago";
|
||||
}
|
||||
if (interval === 1) {
|
||||
return "1 hour ago"
|
||||
}
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval > 1) {
|
||||
return interval + " minutes ago";
|
||||
}
|
||||
if (interval === 1) {
|
||||
return "1 minute ago"
|
||||
}
|
||||
if (seconds > 10) {
|
||||
return Math.floor(seconds) + " seconds ago";
|
||||
}
|
||||
if (seconds > -10) {
|
||||
return "just now"
|
||||
}
|
||||
if (seconds > -60) {
|
||||
return "in " + Math.floor(-seconds) + " seconds";
|
||||
}
|
||||
interval = Math.floor(-seconds / 60);
|
||||
if (interval === 1) {
|
||||
return "in 1 minute";
|
||||
}
|
||||
if (interval < 60) {
|
||||
return "in " + interval + " minutes";
|
||||
}
|
||||
interval = Math.floor(-seconds / 3600);
|
||||
if (interval === 1) {
|
||||
return "in 1 hour";
|
||||
}
|
||||
if (interval > 1) {
|
||||
return "in " + interval + " hours";
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the time from the message
|
||||
function parseTimeString(data) {
|
||||
return ` | ${timeSince(data.time)}, expires in ${timeSince(data.expires)}`
|
||||
}
|
||||
|
||||
// Update time
|
||||
function updateTime() {
|
||||
const timeElements = document.getElementsByClassName('time');
|
||||
for (let i = 0; i < timeElements.length; i++) {
|
||||
const time = timeElements[i];
|
||||
time.textContent = parseTimeString(time.dataset);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new entry to the list
|
||||
function addEntry(data) {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
// Create a new cell for the author
|
||||
const authorCell = document.createElement('td');
|
||||
authorCell.classList.add('author');
|
||||
authorCell.style.fontWeight = 'italic';
|
||||
|
||||
// Create a new cell for the message
|
||||
const messageCell = document.createElement('td');
|
||||
messageCell.classList.add('message');
|
||||
|
||||
// Split the message into author and text
|
||||
const [name, message] = data.message.split(/:\s(.*)/);
|
||||
|
||||
// Create span with the time that passed since the message was sent
|
||||
// and when the message will expire
|
||||
const time = document.createElement('span');
|
||||
time.classList.add('time');
|
||||
time.dataset.time = data.time;
|
||||
time.dataset.expires = data.expires;
|
||||
time.textContent = parseTimeString(data);
|
||||
|
||||
// Set the cell content
|
||||
authorCell.textContent = name + ':';
|
||||
messageCell.innerHTML = message + time.outerHTML;
|
||||
|
||||
// Append the cells to the row and the row to the table
|
||||
row.appendChild(authorCell);
|
||||
row.appendChild(messageCell);
|
||||
|
||||
entryTable.appendChild(row);
|
||||
}
|
||||
|
||||
// Connect to the server to receive new entries
|
||||
function streamEntries() {
|
||||
eventSource.onmessage = (m) => {
|
||||
if (debug) {
|
||||
console.log(m.data);
|
||||
}
|
||||
const data = JSON.parse(m.data)
|
||||
addEntry(data);
|
||||
|
||||
// Play a notification sound for new entries
|
||||
try {
|
||||
if (bellEnabled) {
|
||||
bell.play();
|
||||
}
|
||||
} catch (DOMException) {
|
||||
console.log('The notification sound was blocked by the browser');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize the page
|
||||
function setup() {
|
||||
// Add event listeners
|
||||
submitEntry.addEventListener('click', sendMessage);
|
||||
entryText.addEventListener('keydown', handleKeydown);
|
||||
|
||||
// Start streaming the entries
|
||||
streamEntries();
|
||||
|
||||
// Update the time values every 10 seconds
|
||||
setInterval(updateTime, 10000);
|
||||
|
||||
// Load the name from the local storage
|
||||
name.value = localStorage.getItem('name');
|
||||
|
||||
// Enable the notification sound after 2 seconds
|
||||
setTimeout(() => {
|
||||
bellEnabled = true;
|
||||
}, 2000);
|
||||
|
||||
// Close the connection when the page is closed
|
||||
window.addEventListener('beforeunload', function (e) {
|
||||
e.preventDefault();
|
||||
eventSource.close();
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('load', setup)
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
body {
|
||||
background-color: #01252b;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
h1 span {
|
||||
display: inline-block;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
max-width: 1000px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 84%;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
padding: 8% 4%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#hi {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#rotate {
|
||||
-ms-transition: 0.4s ease-in-out;
|
||||
-webkit-transition: 0.4s ease-in-out;
|
||||
transition: 0.4s ease-in-out;
|
||||
}
|
||||
|
||||
#rotate:hover, #rotate:active {
|
||||
-ms-transform: rotate(180deg); /* IE 9 */
|
||||
-webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.guestbook {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 168px;
|
||||
background: darkslategray;
|
||||
margin: 20px auto;
|
||||
box-shadow: 10px 10px 5px #162222;
|
||||
border-radius: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.guestbook h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.guestbook table {
|
||||
margin: 0 8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.guestbook table td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
white-space: preserve;
|
||||
}
|
||||
|
||||
.author {
|
||||
font-weight: bold;
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.guestbook-form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
margin: 10px auto;
|
||||
box-shadow: 10px 10px 5px #162222;
|
||||
}
|
||||
|
||||
.guestbook-form input {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 90%;
|
||||
resize: none;
|
||||
padding: 10px;
|
||||
background: darkslategray;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
|
||||
.guestbook-form #name {
|
||||
float: left;
|
||||
width: 120px;
|
||||
border-radius: 6px;
|
||||
margin-right: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.guestbook-form #entryText {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.guestbook-form button {
|
||||
float: right;
|
||||
width: 10%;
|
||||
min-width: 72px;
|
||||
height: auto;
|
||||
padding: 10px;
|
||||
border-radius: 0 6px 6px 0;
|
||||
background: #2e6971;;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.time {
|
||||
display: inline;
|
||||
opacity: 0;
|
||||
color: #61959d;
|
||||
font-size: small;
|
||||
transition: opacity 0.5s linear;
|
||||
}
|
||||
|
||||
tr:hover .time {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#error-message {
|
||||
opacity: 0;
|
||||
color: red;
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
transition: opacity 0.5s linear;
|
||||
}
|
||||
|
||||
#error-message.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
|
||||
.guestbook-form {
|
||||
display: block;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.guestbook-form input {
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: 10px 10px 5px #162222;
|
||||
}
|
||||
|
||||
.guestbook-form #name {
|
||||
width: calc(100% - 20px);
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.guestbook-form #entryText {
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.guestbook-form button {
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
box-shadow: 10px 10px 5px #162222;
|
||||
}
|
||||
|
||||
.time {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue