Registra tu proyecto para impulso digital
html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Botones Magnéticos con Efecto Parallax</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="button-container">
<button class="magnetic-button">¡Haz clic aquí!</button>
</div>
<script src="script.js"></script>
</body>
</html>
css
/* styles.css */
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #f0f0f0;
}
.button-container {
position: relative;
}
.magnetic-button {
padding: 15px 30px;
border: none;
background-color: #ff6f61;
color: white;
font-size: 16px;
font-weight: bold;
border-radius: 5px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.magnetic-button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 150%;
height: 150%;
background-color: rgba(0, 0, 0, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: transform 0.3s ease;
z-index: 0;
}
.magnetic-button:hover {
transform: scale(1.1);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.magnetic-button:hover::before {
transform: translate(-50%, -50%) scale(1.3);
}
javascript
// script.js
document.addEventListener('DOMContentLoaded', () => {
const button = document.querySelector('.magnetic-button');
document.addEventListener('mousemove', (event) => {
const { clientX: mouseX, clientY: mouseY } = event;
const { offsetLeft: buttonX, offsetTop: buttonY, offsetWidth: buttonWidth, offsetHeight: buttonHeight } = button;
const buttonCenterX = buttonX + buttonWidth / 2;
const buttonCenterY = buttonY + buttonHeight / 2;
const deltaX = mouseX - buttonCenterX;
const deltaY = mouseY - buttonCenterY;
const maxOffset = 20;
const offsetX = Math.max(-maxOffset, Math.min(maxOffset, deltaX / 10));
const offsetY = Math.max(-maxOffset, Math.min(maxOffset, deltaY / 10));
button.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
});
});
css
body {
background-image: url("../img/noise.gif"), radial-gradient(circle, rgb(242, 251, 248) 0%, rgb(248, 254, 252) 100%);
background-size: cover;
background-repeat: no-repeat;
background-blend-mode: overlay;
}
css
@keyframes distortion {
0% {
transform: scale(1) skew(0deg, 0deg);
}
25% {
transform: scale(1.05) skew(1deg, -1deg);
}
50% {
transform: scale(1) skew(-1deg, 1deg);
}
75% {
transform: scale(1.05) skew(1deg, 0deg);
}
100% {
transform: scale(1) skew(0deg, 0deg);
}
}
css
.producttags a:hover {
color: black;
background: #fce4cc;
text-decoration: none;
animation: distortion 0.3s ease-in-out; /* Aplica la animación de distorsión */
}
css
.producttags a:before,
.producttags a:after {
content: "";
position: absolute;
/* Estilos adicionales */
transition: opacity 0.3s ease-in-out; /* Transición para suavizar la desaparición */
}
.producttags a:hover:before,
.producttags a:hover:after {
opacity: 0; /* O utiliza visibility: hidden; */
}
css
.producttags a:hover::after {
backdrop-filter: blur(10px); /* Aplica desenfoque */
}
css
@keyframes distortion {
0% {
transform: scale(1) skew(0deg, 0deg);
}
25% {
transform: scale(1.05) skew(1deg, -1deg);
}
50% {
transform: scale(1) skew(-1deg, 1deg);
}
75% {
transform: scale(1.05) skew(1deg, 0deg);
}
100% {
transform: scale(1) skew(0deg, 0deg);
}
}
.producttags {
list-style: none;
position: relative;
clear: both;
display: block;
padding-bottom: 20px;
margin-bottom: 20px;
}
.producttags li, .producttags a {
float: left;
height: 24px;
line-height: 24px;
position: relative;
font-size: 11px;
}
.producttags a {
margin-left: 20px;
padding: 0 10px 0 12px;
background: black;
color: white;
text-decoration: none;
border-bottom-right-radius: 4px;
border-top-right-radius: 4px;
position: relative;
overflow: hidden;
}
.producttags a:visited {
color: #fce4cc;
}
.producttags a:before,
.producttags a:after {
content: "";
position: absolute;
top: 0;
left: -12px;
width: 0;
height: 0;
border-color: transparent black transparent transparent;
border-style: solid;
border-width: 12px 12px 12px 0;
transition: opacity 0.3s ease-in-out; /* Transición para suavizar la desaparición */
}
.producttags a:after {
background: #fff;
border-radius: 2px;
box-shadow: -1px -1px 2px #004977;
}
.producttags a:hover {
color: black;
background: #fce4cc;
text-decoration: none;
animation: distortion 0.3s ease-in-out; /* Aplica la animación de distorsión */
}
.producttags a:hover:before,
.producttags a:hover:after {
opacity: 0; /* Pseudo-elementos se hacen invisibles durante el efecto de distorsión */
}
perl awstats.pl -config=misitio -update
pip install Flask Flask-SQLAlchemy Flask-WTF pyotp qrcode[pil]
your_project/
app.py
templates/
base.html
login.html
register.html
two_factor.html
static/
from flask import Flask, render_template, redirect, url_for, request, flash, session
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
import pyotp
import qrcode
import qrcode.image.svg
from io import BytesIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), nullable=False, unique=True)
password = db.Column(db.String(150), nullable=False)
otp_secret = db.Column(db.String(16), nullable=False)
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=150)])
password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
class TwoFactorForm(FlaskForm):
token = StringField('Token', validators=[DataRequired()])
submit = SubmitField('Verify')
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
otp_secret = pyotp.random_base32()
new_user = User(username=form.username.data, password=form.password.data, otp_secret=otp_secret)
db.session.add(new_user)
db.session.commit()
flash('Account created! Please log in.', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.password == form.password.data:
session['username'] = user.username
session['otp_secret'] = user.otp_secret
return redirect(url_for('two_factor'))
else:
flash('Login Unsuccessful. Please check username and password', 'danger')
return render_template('login.html', form=form)
@app.route('/two_factor', methods=['GET', 'POST'])
def two_factor():
form = TwoFactorForm()
otp_secret = session.get('otp_secret')
if not otp_secret:
return redirect(url_for('login'))
if form.validate_on_submit():
user = User.query.filter_by(username=session.get('username')).first()
totp = pyotp.TOTP(user.otp_secret)
if totp.verify(form.token.data):
session['authenticated'] = True
flash('Logged in successfully!', 'success')
return redirect(url_for('dashboard'))
else:
flash('Invalid token. Please try again.', 'danger')
return render_template('two_factor.html', form=form)
@app.route('/dashboard')
def dashboard():
if not session.get('authenticated'):
return redirect(url_for('login'))
return f"Welcome to your dashboard, {session['username']}!"
@app.route('/qr_code')
def qr_code():
otp_secret = session.get('otp_secret')
if not otp_secret:
return redirect(url_for('login'))
totp = pyotp.TOTP(otp_secret)
img = qrcode.make(totp.provisioning_uri(session.get('username'), issuer_name="YourApp"))
buffer = BytesIO()
img.save(buffer, format='PNG')
buffer.seek(0)
return buffer.getvalue(), 200, {'Content-Type': 'image/png'}
if __name__ == '__main__':
db.create_all()
app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2FA Tutorial</title>
</head>
<body>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block content %}
<form method="POST" action="">
{{ form.hidden_tag() }}
<div>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</div>
<div>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</div>
<div>
{{ form.confirm_password.label }}<br>
{{ form.confirm_password(size=32) }}<br>
{% for error in form.confirm_password.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</div>
<div>
{{ form.submit() }}
</div>
</form>
{% endblock %}
{% extends "base.html" %}
{% block content %}
<form method="POST" action="">
{{ form.hidden_tag() }}
<div>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</div>
<div>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</div>
<div>
{{ form.submit() }}
</div>
</form>
{% endblock %}
{% extends "base.html" %}
{% block content %}
<img src="{{ url_for('qr_code') }}" alt="QR Code"><br>
Scan the QR code above with your authenticator app and enter the token below.<br>
<form method="POST" action="">
{{ form.hidden_tag() }}
<div>
{{ form.token.label }}<br>
{{ form.token(size=32) }}<br>
{% for error in form.token.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</div>
<div>
{{ form.submit() }}
</div>
</form>
{% endblock %}
python app.py
/gateway/plugin/WebFeedGatewayPlugin/atom
Botones Magnéticos con Animaciones y Efecto Parallax
por BarbaraEberle
Jul 24, 2024 |
Crear un Fondo con Degradado Verde y Ruido Estático en Thirty Bees
por BarbaraEberle
Jul 24, 2024 |
Efectos de Distorsión y Desenfoque en CSS con Control de Pseudo-elementos
por BarbaraEberle
Jul 24, 2024 |
AWStats
por MCE. Mauricio Eberle Morales
Jul 23, 2024 |
Proyecto Nearshoring IBERO
por MCE. Mauricio Eberle Morales
Jul 23, 2024 |
ConectaTech: Alfabetización Digital para Todos
por Beatriz Morales Granados
Jul 23, 2024 |
Implementar la autenticación de dos factores (2FA
por MCE. Mauricio Eberle Morales
Jul 23, 2024 |
El Peligro de los Esquemas Piramidales Dirigidos a Mujeres
por MCE. Mauricio Eberle Morales
Jun 20, 2024 |
Dialog Flow
por MCE. Mauricio Eberle Morales
Jun 19, 2024 |
Integración ATOM
por Kat-IA
Jun 19, 2024 |
Únete a nosotros en nuestro compromiso de promover el acceso abierto y la difusión del conocimiento. Tu apoyo financiero nos permite continuar con nuestros proyectos de Open Access. Además, como agradecimiento, recibirás una hermosa página web como regalo. ¡Juntos podemos hacer la diferencia en el mundo del conocimiento abierto!