Skip to content

Instantly share code, notes, and snippets.

@warderer
Last active July 7, 2025 00:16
Show Gist options
  • Select an option

  • Save warderer/393cae36d19a570df4e883855acabee8 to your computer and use it in GitHub Desktop.

Select an option

Save warderer/393cae36d19a570df4e883855acabee8 to your computer and use it in GitHub Desktop.
[React Hook Form Class] Master in Frontend forms class base code, module 7 class 1 #devf #react
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.app-header {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
padding: 2rem 0;
}
.app-title {
font-size: 2.5rem;
font-weight: 700;
color: white;
text-align: center;
margin-bottom: 0.5rem;
}
.app-subtitle {
font-size: 1.1rem;
color: rgba(255, 255, 255, 0.8);
text-align: center;
}
.app-main {
flex: 1;
padding: 3rem 0;
display: flex;
align-items: center;
min-height: calc(100vh - 200px);
height: 100%;
}
.app-footer {
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border-top: 1px solid rgba(255, 255, 255, 0.1);
padding: 1.5rem 0;
text-align: center;
color: rgba(255, 255, 255, 0.8);
}
.newpost-container {
background: white;
border-radius: 20px;
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.1);
padding: 2.5rem;
max-width: 800px;
margin: 0 auto;
}
.newpost-header {
text-align: center;
margin-bottom: 2.5rem;
}
.newpost-header h1 {
font-size: 2.2rem;
font-weight: 600;
color: #2d3748;
margin-bottom: 0.5rem;
}
.newpost-header p {
font-size: 1.1rem;
color: #718096;
}
.newpost-form {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.form-group {
display: flex;
flex-direction: column;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
.form-label {
font-weight: 600;
color: #2d3748;
margin-bottom: 0.5rem;
font-size: 0.95rem;
}
.form-input,
.form-textarea,
.form-select {
padding: 0.75rem 1rem;
border: 2px solid #e2e8f0;
border-radius: 12px;
font-size: 1rem;
transition: all 0.3s ease;
background: white;
}
.form-input:focus,
.form-textarea:focus,
.form-select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.form-textarea {
resize: vertical;
min-height: 120px;
}
.form-input.error,
.form-textarea.error,
.form-select.error {
border-color: #e53e3e;
}
.error-message {
color: #e53e3e;
font-size: 0.85rem;
margin-top: 0.25rem;
font-weight: 500;
}
.form-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
margin-top: 1rem;
}
.btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.btn-primary:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
}
.btn-primary:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-secondary {
background: #f7fafc;
color: #4a5568;
border: 2px solid #e2e8f0;
}
.btn-secondary:hover {
background: #edf2f7;
transform: translateY(-1px);
}
/* Efectos de animación para el formulario */
.newpost-container {
animation: fadeInUp 0.6s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.form-group {
animation: slideIn 0.4s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* Responsive design */
@media (max-width: 768px) {
.newpost-container {
padding: 1.5rem;
margin: 1rem;
}
.form-row {
grid-template-columns: 1fr;
}
.form-actions {
flex-direction: column;
}
.app-title {
font-size: 2rem;
}
.newpost-header h1 {
font-size: 1.8rem;
}
}
@media (max-width: 480px) {
.newpost-container {
padding: 1rem;
margin: 0.5rem;
}
.app-title {
font-size: 1.5rem;
}
.newpost-header h1 {
font-size: 1.5rem;
}
}
import './NewPost.css'
const NewPost = () => {
const onSubmit = async (data) => {
try {
// Simular envío de datos
await new Promise(resolve => setTimeout(resolve, 1000))
console.log('Datos del post:', data)
alert('¡Post creado exitosamente!')
// TODO: Añadir reset
} catch (error) {
console.error('Error al crear el post:', error)
alert('Error al crear el post. Intenta nuevamente.')
}
}
const categories = [
'Tecnología',
'Programación',
'Diseño',
'Marketing',
'Negocios',
'Educación',
'Estilo de vida',
'Salud',
'Viajes'
]
return (
<div className='newpost-container'>
<div className='newpost-header'>
<h1>Crear Nueva Entrada</h1>
<p>Comparte tus ideas con el mundo</p>
</div>
<div className='newpost-form'>
<div className='form-group'>
<label htmlFor='title' className='form-label'>
Título del Post *
</label>
<input
type='text'
id='title'
className='form-input' // TODO: Añadir clase de error si hay errores
placeholder='Ingresa un título para tu post'
// TODO: Registrar input title
/>
{/* TODO: Mostrar mensaje de error */}
</div>
<div className='form-group'>
<label htmlFor='content' className='form-label'>
Contenido *
</label>
<textarea
id='content'
rows='6'
className='form-textarea' // TODO: Añadir clase de error si hay
placeholder='Escribe el contenido de tu post aquí...'
// TODO: Registrar input content
/>
{/* TODO: Mostrar mensaje de error */}
</div>
<div className='form-row'>
<div className='form-group'>
<label htmlFor='category' className='form-label'>
Categoría *
</label>
<select
id='category'
className='form-select ' // TODO: Añadir clase de error si hay
// TODO: Registrar input category
>
<option value=''>Selecciona una categoría</option>
{categories.map((category) => (
<option key={category} value={category}>
{category}
</option>
))}
</select>
{/* TODO: Mostrar mensaje de error */}
</div>
<div className='form-group'>
<label htmlFor='author' className='form-label'>
Autor *
</label>
<input
type='text'
id='author'
className='form-input ' // TODO: Añadir clase de error si hay
placeholder='Tu nombre'
// TODO: Registrar input author
/>
{/* TODO: Mostrar mensaje de error */}
</div>
</div>
<div className='form-group'>
<label htmlFor='publishDate' className='form-label'>
Fecha de Publicación *
</label>
<input
type='datetime-local'
id='publishDate'
className='form-input ' // TODO: Añadir clase de error si hay
// TODO: Registrar input publishDate
/>
{/* TODO: Mostrar mensaje de error */}
</div>
<div className='form-actions'>
<button
type='button'
className='btn btn-secondary'
onClick={() => {}} // TODO: Añadir reset del formulario
>
Limpiar
</button>
<button
type='button'
className='btn btn-primary'
// TODO: Añadir lógica para deshabilitar si se esta enviando el formulario.
onClick={onSubmit} // TODO: Actualizar función de envío
>
{/* TODO: Añadir texto condicional al botón */}
Publicar Post
</button>
</div>
</div>
</div>
)
}
export default NewPost
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment