Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Usuario Invitado

#51
Java / Subir archivos con Servlet
6 Julio 2015, 00:20 AM
Subir archivos en Java es realmente muy sencillo. Ya Java nos provee interfaces como Part para facilitarnos el trabajo. Veamos un ejemplo:

Vamos con nuestro sencillo formulario:


Código (html5) [Seleccionar]

<h1>Subir archivos</h1>
    <form method="post" action="upload" enctype="multipart/form-data">
    <fieldset>
    <legend>Formulario de subida</legend>
    <input type="file" name="files" id="files" multiple/>
        <button type="submit">Subir</button>
    </fieldset>
</form>


Como podemos observar no hay nada del otro mundo. Simplemente un input tipo file e indicamos que se podrán elegir múltiples archivos. Por últmo, el botón submit.


Servlet

Nuestro servlet será como cualquier otro, pero añadiremos la anotación @MultipartConfig, que básicamente, identificará el servlet como un servlet multipart/form-data.

Código (java) [Seleccionar]
@WebServlet(name = "UploadServlet", urlPatterns = {"/upload"})
@MultipartConfig(location="D:/uploads")
public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
   
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        Collection<Part> parts = request.getParts();
        for(Part part : parts) {
        part.write(getFileName(part));
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    public String getFileName(Part part) {
        String contentHeader = part.getHeader("content-disposition");
        String[] subHeaders = contentHeader.split(";");
        for(String current : subHeaders) {
            if(current.trim().startsWith("filename")) {
            int pos = current.indexOf('=');
                String fileName = current.substring(pos+1);
                return fileName.replace("\"", "");
            }
        }
        return null;
    }
}


El atributo location sirve para especificar la ruta donde se guardarán los archivos recibidos. Ésto porsupuesto puede hacerse desde código también. En mi caso, he decidido guardarlas en D:/uploads.

Primero, recibimos todos los part mediante el método getParts() del objeto HttpServletRequest. Cada part viene a ser una parte que representa a cada elemento enviado. El payload de la petición se ve así:

Código (text) [Seleccionar]
------WebKitFormBoundaryKZUc66kZeBth3nDc
Content-Disposition: form-data; name="files"; filename="jsf-scopes.png"
Content-Type: image/png


------WebKitFormBoundaryKZUc66kZeBth3nDc
Content-Disposition: form-data; name="files"; filename="navbar.png"
Content-Type: image/png


Donde Content-Disposition y Content-Type son las cabeceras de las peticiones por cada part (elemento) enviado.  Es importante saber la anatomía de éstas peticiones, porque luego las usaremos para obtener ciertos datos,  como el nombre de los archivos.

Luego, recorremos los parts y por cada uno de ellos, obtenemos su nombre llamando al método getFileName el cual recibe un part y devuelve el nombre del archivo/elemento al que corresponde:

Código (java) [Seleccionar]
public String getFileName(Part part) {
        String contentHeader = part.getHeader("content-disposition");
        String[] subHeaders = contentHeader.split(";");
        for(String current : subHeaders) {
            if(current.trim().startsWith("filename")) {
            int pos = current.indexOf('=');
                String fileName = current.substring(pos+1);
                return fileName.replace("\"", "");
            }
        }
        return null;
    }


Primero obtenemos la cabecera content-disposition la cual como vimos, almacena los datos del elemento enviado. Ahora, obtenemos los datos de esa cabecera y les llamaremos subHeaders. Los obtenemos diviendo el contenido de la cabecera por puntos y comas (;) porque así está formada la petición.

En éste punto ya tenemos los siguientes datos:

  • form-data
  • name
  • filename

    El que nos interesa es filename ya que éste almacena el nombre del archivo enviado. Comprobamos si la subHeader actual comienza con 'filename', si es así,  obtenemos la posición del caracter '=' para obtener todo lo que hay hacia la derecha, que es lo que nos interesa: el nombre del archivo. Por último, reemplazamos las comillas por nada (eliminar) y eliminamos los espacios en blanco al inicio/final del nombre del archivo. El resultado, el nombre del archivo solamente.

    Una vez que obtenemos el nombre del archivo asociado a cada part, los escribimos en el directorio especificado por el atributo location, que será D:/uploads:

    Código (java) [Seleccionar]

    part.write(getFileName(part));


    Por último, verificamos si se han subido  los archivos:



    Eso es todo. ¿Quién dijo que Java es difícil? :P
#52
Se ve así porque te falta agregar un css reset (indispensable). Si lo agregas, verás que la lista se se muestra correctamente.

El reset que uso yo es Normalize. Sería bueno también que agregaras Prefixfree que éste agrega los prefijos css por tí.

Checka a ver si te sirve: Menu responsivo. Redimensiona el browser para ver como cambia su forma el menú.

Probado en IE11, Firefox/Chrome/Safari última versión.
#53
Te hice una, salió parecida: ver fiddle

#54
Por si no haz visto el link que te proporcioné, JavaFX tiene un GUI Builder muy potente, llamado JavaFX Scene Builder. En el link del tutorial te proporcionan links para su descarga , el tutorial lo utiliza para toda la parte gráfica.
#55
Redirección es cuando te mueves entre vistas (HTML). Lo que quieres es solo moverte hacia una sección dentro del mismo documento.

Supongamos que tienes un elemento a:

Código (html4strict) [Seleccionar]
<a href="#seccion1" id="link1">Ir a sección 1</a>

Entonces, el target debería tener el indentificador #seccion1:

Código (html4strict) [Seleccionar]
<div id="seccion1">
    <!-- contenido aqui -->
</div>


Ya está. Cuando se haga click en el hyperlink, se moverá desde el nav hasta el div objetivo.

La transición es instantánea, por lo que no es muy user-friendly. Puedes hacer que se deslice suavemente hacia el div objetivo con un poco de código javascript:

Código (javascript) [Seleccionar]
$('#link1').on('click', function(e) {
    e.preventDefault();
    $("html, body").animate({scrollTop: $('#section1').offset().top }, 1000);
});


Demo en JSFiddle: http://jsfiddle.net/vbxsuc4c/
#56
1. void no es un modificador válido para una clase.
2. El método edad devuelve un tipo de dato inválido (inte).
3. Dentro del método edad, se declara la variable local 'e' como Int, lo cual es inválido por ser inexistente.
4. Se le asigna un valor tipo String a la variable 'e', que ya por sí es inválida, pero, si fuera 'e' de tipo int o Integer, habría una excepción al intentar asignarle a un tipo de dato numérico un tipo de dato texto.
5. Falta un punto y coma (;) al imprimir la variable 'e'.
6. La clase Jalado que extiende de Estudiante, tiene un modificador de acceso inválido (Public), los modificadores de acceso comienzan en minúscula. Además, tiene un modificador inválido (void) en la declaración (ver pt 1).
7. La impresión dentro del método obtener_notas, es inválida. Falta punto y coma (;) al final de la expresión.

Plus: Si bien no se considera oficialmente un error, utilizar la nomenclatura de underscore para métodos y variables (no constantes) se considera un mal hábito ya que, la nomenclatura oficialmente utilizada en Java para variables y métodos es camelCase, y para clases PascalCase.
#57
Solo paso para recomendarte JavaFX. Swing será marcado como deprecated en futuras versiones. JavaFX es el reemplazo de Swing. Con JavaFX puedes crear animaciones, agregarle CSS a tus aplicaciones y hacer que se vean como tú quieres, además, predomina el patrón MVC (modelo - vista - controlador) lo que hará tus apps altamente eficientes.

Tutorial: hacer una agenda de contactos con JavaFX y CSS
#58
No me imagino programar una aplicación mediana con un editor de textos.

Ventajas de un IDE:

  • Autocompletado
  • Linter (verificación de code en tiempo real)
  • Debug
  • Generación de código (Mapeos ORM, configuraciones)
  • Soporte para frameworks (Zend, CodeIgniter, Symfony, etc)
  • Soporte para ORM (Doctrine)
  • Soporte para tecnologías cliente (Angular, jQuery)
  • Soporte para test unitarios (PHPUnit)
  • etc...

    Desventajas:

  • Malo para novatos. La generación de código les imposabilita un poco aprender a hacer las cosas por su cuenta y entender el porqué de las cosas.
  • Consume mucho más recursos que un editor.


    No dudes en elegir un IDE si sabes lo que estás haciendo. Te ayudará mucho y te reducirá mucho el tiempo de desarrollo.

    En mi caso (Java EE) cuando no uso IntelliJ IDEA, utilizo Sublime Text 3 para la parte front, ya que le veo más caso usarlo para diseño web. Si estoy usando IntelliJ, lo hago todo allí. Tiene muy buen soporte para tecnologías front end.


    Salu2.
#59
Desarrollo Web / [CSS3] Login + preloader
25 Junio 2015, 00:37 AM
Con el avance de las tecnologías de la web, se pueden hacer cada vez cosas mas bonitas, cosas que sin duda pueden dar una buena UX al usuario de nuestra web o aplicación web.

En el presente texto, haremos un login con algunas animaciones y un preloader que seguramente habrás visto en algunas webs cuando te logueas y aparece algo que demuestra que la web está cargando (animaciones por lo general).

(Click en la imagen para ir al demo)

CitarUsuario: john.doe@gmail.com
Contraseña: abc123



1. INDEX



  • Necesitaremos importar fontawesome y nornalize.

    La estructura HTML para nuestro login es sencilla:

    Código (html5) [Seleccionar]

    <!DOCTYPE html>
    <html lang="es">
    <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/vendor/normalize.css"/>
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"/>
    <link rel="stylesheet" href="css/main.css"/>
    <title>Login</title>
    </head>
    <body>
    <section class="main">
    <form id="loginFrm" class="form">
    <figure class="tooltip"></figure>
    <section class="form-head">
    <span>Login</span>
    <figure class="logo"></figure>
    </section>
    <section class="form-body">
    <div class="group">
    <label for="user">Email:</label>
    <input type="text" id="user" class="txt">
    </div>
    <div class="group">
    <label for="pass">Password:</label>
    <input type="password" id="pass" class="txt">
    </div>
    <div class="group flex-end">
    <button type="submit" id="login" class="btn btn-radical">login</button>
    </div>
    </section>
    </form>
    </section>
    <script>
    'use strict';
    window.addEventListener('load', function() {
    let main = document.querySelector('.main');
    main.classList.add('visible');
    });
    </script>
    <script src="js/auth.js"></script>
    </body>
    </html>


    La estructura es muy simple. Consta de un formulario con dos partes:


    • form-head: Aquí tendremos el título del form y el pin (el círculo con el ícono de un usuario).
    • form-body: Aquí tendremos todos los grupos (label/inputs) y botones.

    Vemos que hay un elemento con la clase 'tooltip'. Bien, éste elemento es como su nombre lo dice, un tooltip en cual nos servirá para mostrar los errores de autenticación.

    Ahora veamos el CSS. Lo primero que haremos será aplicar la propiedad box-sizinz: border-box a HTML y hacer que todos los elementos hereden de él esa propiedad.

    Código (css) [Seleccionar]

    html {
    box-sizing: border-box;
    }
    *, *:before, *:after {
    box-sizing: inherit;
    }


    Luego, aplicamos estilos al container general, es decir, main:

    Código (css) [Seleccionar]

    .main {
    align-items: center;
    background: rgba(136,211,124,1);
    background: linear-gradient(to bottom, rgba(136,211,124,1) 0%,
    rgba(136,211,124,1) 50%,
    rgba(190,144,212,1) 51%,
    rgba(190,144,212,1) 71%,
    rgba(190,144,212,1) 100%);
    background-repeat: repeat;
    display: flex;
    height: 100vh;
    justify-content: center;
    opacity: 0;
    transition: all .2s linear;
    visibility: hidden;
    }
    .main.visible {
    opacity: 1;
    visibility: visible;
    }


    Aplicamos display: flex, align-items: center y justify-content: center para centrar el formulario, un centrado perfecto. Para ésto, .main debe de tener un alto, el cual se lo especificamos en 100vh (100 view height).

    También, le damos una opacidad de 0 y una visibilidad oculta (hidden), además un transition: all .2s ease-in para que al cambiar opacity a 1 y visibility a visible, el efecto sea suave y bonito. Aquí es donde toma importancia .visible, que solamente cambia la opacidad y la visibilidad de .main.

    Ahora vayamos con el formulario:

    Código (css) [Seleccionar]

    .form {
    background-color: #f7f7f7;
    border: none;
    border-radius: 2px;
    box-shadow: 0 2px 5px rgba(0,0,0,.25),
    0 -1px 5px rgba(0,0,0,.1);
    position: relative;
    width: 350px;
    }


    Nada relevante. Solo tiene un color blanco humo, sin bordes, un redondeado de 2px, una sombra, un ancho y lo importante, una posición relative. Esta propiedad nos permitirá situar el pin y el tooltip con relación al formulario.

    Código (css) [Seleccionar]

    .form-head {
    align-items: center;
    border-radius: 2px 2px 0 0;
    border-bottom: 2px solid #9B59B6;
    display: flex;
    height: 45px;
    }
    .form-head > span {
    color: #555;
    font-family: 'segoe ui';
    font-size: 17pt;
    font-weight: lighter;
    margin-left: 12px;
    }


    La cabecera del formulario no tiene nada que explicar. Vayamos con el pin:

    Código (css) [Seleccionar]

    .form-head .logo {
    background-position: center;
    background-repeat: no-repeat;
    background-image: url('http://urbita.com/img/default/default_user_256.png');
    background-size: cover;
    border-radius: 100%;
    box-shadow: 0px 2px 5px rgba(0,0,0,.25);
    height: 85px;
    left: calc(50% - 38.5px);
    margin: 0px;
    position: absolute;
    top: calc(0% - 38.5px);
    width: 85px;
    }


    El pin tiene un ancho y alto de 85px, además un border-radius de 100%, lo que le dará la forma de un círculo. Tiene una pequeña sombra con un offset Y de 2px, lo que hará que la sombra se despligue hacia abajo. Las propiedades de background permiten que la imagen se centre y que cubra el tamaño del círculo.

    La parte más importante es la propiedad position: absolute. Esta instrucción nos permite posicionar el pin de acuerdo al padre. Ahora, podemos centrarlo horizontalmente con solo left: calc(50% - 38.5px) y verticalmente con top: calc(0% - 38.5px) (por cuestión de entendimiento, si preguntas porqué no hice -38px xD). Ahora tenemos en pin centrado en la cabecera. ¿Fácil no?

    Ahora, hagamos algo de magia. Hagamos al pin animado, para ésto, usaremos keyframes:

    Código (css) [Seleccionar]

    @keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(1800deg); }
    }


    La animación se llamará spin, y el elemento que la use empezará con una rotación de 0 grados y terminará con una rotación de 1800 grados (5 vueltas completas). Ahora, el pin la usará cuando tenga la clase 'auth', que informa que se ha hecho una autenticación en el formulario:

    Código (css) [Seleccionar]

    .form-head .logo.auth {
    animation-name: spin;
    animation-duration: 3000ms;
    animation-iteration-count: 1;
    animation-timing-function: linear;
    animation-play-state: running;
    animation-fill-mode: forwards;
    animation-delay: 0s;
    }


    La duración será de 3 segundos. Solo iterará una vez, será a una velocidad plana (linear) y sin tardanza antes de empezar la animación.

    Ahora vayamos con el cuerpo del formulario:

    Código (css) [Seleccionar]

    .form-body {
    padding: 40px 25px 10px 25px;
    }
    .group {
    align-items: center;
    display: flex;
    margin-bottom: 10px;
    }
    .group > label {
    color: #777;
    display: block;
    flex-grow: 1;
    font-family: 'segoe ui';
    }


    El cuerpo de formulario tendrá un padding de 40px hacia arriba, 25px hacia los lados y 10px hacia abajo (lo último para contrarrestrar el margin-bottom de los grupos, que contiene los label y los input. Los labels serán en forma de bloque y con un flex-grow: 1 que hará que el label tenga un tamaño definido.

    Pondremos éstas 2 clases como apoyo, la primera para alinear los elementos hacia el final del bloque, y el otro para un centrado absoluto:

    Código (css) [Seleccionar]

    .flex-end {
    justify-content: flex-end;
    }
    .flex-abs-center {
    align-items: center;
    justify-content: center;
    }


    Ahora vayamos con los textboxes:

    Código (css) [Seleccionar]

    .txt {
    border: 1px solid #ddd;
    border-radius: 2px;
    color: #777;
    font-family: 'segoe ui';
    font-size: .9rem;
    outline: none;
    padding: .35rem .5rem;
    transition: all .2s ease;
    }
    .txt.invalid {
    border-color: rgba(231,76,60,.7);
    }
    .txt:hover {
    border-color: #ccc;
    }
    .txt:focus {
    border-color: #bbb;
    }


    Nada del otro mundo. La clase invalid solo pintará el borde del textbox de rojo. Ahora los botones:

    Código (css) [Seleccionar]

    .btn {
    border: none;
    border-radius: 2px;
    box-shadow: 0 2px 5px rgba(0,0,0,.2);
    font-family: 'segoe ui';
    font-size: .9rem;
    outline: none;
    padding: .45rem 1.25rem;
    text-transform: uppercase;
    transition: all .3s ease;
    }
    .btn-radical {
    background-color: #F62459;
    color: rgba(255,255,255,.9);
    margin-top: 15px;
    }
    .btn-radical:hover {
    background-color: #DC1F4E;
    }


    Tampoco nada que destacar. Un redondeado de 2px, fuente segoe ui, una ligera sombra y un padding. btn-radical solo le da color (radical) y un margin-top de 15px.

    Por último, finalizaremos con el tooltip:

    Código (css) [Seleccionar]

    .form .tooltip {
    background-color: rgba(0,0,0,.5);
    border-radius: 5px;
    box-shadow: 0px 2px 5px rgba(0,0,0,.25);
    color: rgba(255,255,255,.8);
    font-family: 'segoe ui';
    font-size: .9rem;
    height: 100px;
    left: calc(100% - 35px);
    margin: 0;
    padding: .7rem .6rem;
    opacity: 0;
    position: absolute;
    text-align: center;
    top: -140%;
    transition: all .4s ease-in;
    visibility: hidden;
    width: 200px;
    }


    El tooltip tiene un alto de 200px y un ancho de 100px. Tiene una posición absoluta, lo cual nos hace ubicarlo fácilmente de acuerdo a su padre (formulario). Le damos un left para que quede tirado más a la derecha y un top negativo muy grande para desplazarlo muy arriba, además una opacidad de 1.  Le damos un top muy alto porque en la transición, lo bajaremos y así da la impresión que viene aparece de la nada (por la opacidad también).

    Para hacer el efecto de la flecha, jugaremos un poco con las pseudoclases :before:

    Código (css) [Seleccionar]

    .form .tooltip:before {
    border-color: rgba(0,0,0,.5) transparent;
    border-style: solid;
    border-width: 10px 10px 0px 10px;
    content: "";
    left: 10px;
    position: absolute;
    bottom: -10px;
    }[/coder]

    Por último, para hacerlo visible, aplicaremos una clase:

    [code=css]
    .form .tooltip.visible {
    opacity: 1;
    top: -50%;
    visibility: visible;
    }


    La clase visible, cambia la opacidad del tooltip, visiblidad y le da un top de -50%. Ésto lo que genera, es un efecto que el tooltip viene de arriba y en el camino se hace visible.

    Código JS

    Código (javascript) [Seleccionar]

    'use strict';
    document.addEventListener('DOMContentLoaded', function() {
    let loginFrm = document.querySelector('#loginFrm');

    loginFrm.addEventListener('submit', function(e) {
    e.preventDefault();

    const ANIMATION_TIMEOUT = 3000; // duration of logo animation
    let logo = document.querySelector('.logo');
    let user = document.querySelector('#user').value.toLowerCase();
    let pass = document.querySelector('#pass').value;

    // if logo already is animated, the info is already processing
    if(logo.classList.contains('auth')) {
    return false;
    }

    logo.classList.add('auth'); // start animation

    // check credentials
    if(user == 'john.doe@gmail.com' && pass == 'abc123') {
    window.setTimeout(function() {
    sessionStorage.setItem('full_access', false);
    window.location.href = 'views/home.html';
    }, ANIMATION_TIMEOUT);
    } else {
    window.setTimeout(function() {
    logo.classList.remove('auth'); // remove animation of logo
    showTooltip();
    }, ANIMATION_TIMEOUT);
    }
    });

    // show and hide tooltip
    function showTooltip() {
    let tooltip = loginFrm.querySelector('.tooltip');
    tooltip.textContent = 'El email o contraseña ingresados no son correctos. Verifique e inténtelo nuevamente.';
    tooltip.classList.add('visible');
    // after 4 seconds, the tooltip disappear
    window.setTimeout(function() {
    tooltip.classList.remove('visible');
    }, 4000);
    }
    }); // end script


    El script es muy simple. Escuchamos por evento submit del formulario y obtenemos lo que se ha ingresado en las cajas de texto; también añadimos una constante llamada ANIMATION_TIMEOUT que especifica el tiempo que durará la animación del pin.

    Añadimos la clase 'auth' al pin para empezar la animación. Comprueba las credenciales y si coinciden crear una sessión para el usuario (HTML5 WebStorage) y redirige hacia home, todo ésto con un delay del mismo tiempo que dura la animación, esto es, que una vez que acaba la animación, se redigirá hacia home.

    Si las credenciales no coindicen, quitamos la clase 'auth' del pin para poder volver a iniciar la animación las veces que se requiera. Además, mostramos el tooltip informando de los errores de credenciales. El mismo tooltip desaparecerá al cabo de 4 segundos.

    El script embebido lo único que hace es hacer visible el index para darle el efecto de 'aparición':

    Código (javascript) [Seleccionar]

    'use strict';
    window.addEventListener('load', function() {
    let main = document.querySelector('.main');
    main.classList.add('visible');
    });




    2. HOME



    HTML

  • Normalize.css requerido
  • Prefixfree requerido

    Código (html5) [Seleccionar]

    <!DOCTYPE html>
    <html lang="es">
    <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="../css/vendor/normalize.css"/>
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"/>
    <link rel="stylesheet" href="../css/home.css"/>
    <script src="js/vendor/prefixfree.min.js"></script>
    <title>Home page</title>
    </head>
    <body>
    <section class="preload"><i class="fa fa-4x fa-circle-o-notch fa-spin"></i></section>
    <section class="main">
    <header>
    <nav class="navbar">
    <!-- brand -->
    <a href="#" class="brand">Oh yeah!<i class="fa fa-2x fa-hand-o-right"></i></a>
    <!-- menu -->
    <ul class="menu">
    <li><a href="#">Messages<i class="fa fa-envelope"></i></a></li>
    <li>
    <a href="#">John doe<i class="fa fa-caret-down"></i></a>
    <ul>
    <li><a href="#" id="profile-img">
    <img src="http://i.imgur.com/IxWfQy2.jpg"/></a>
    </li>
    <li><a href="#">Profile<i class="fa fa-user"></i></a></li>
    <li><a href="#">Settings<i class="fa fa-cog"></i></a></li>
    <li><a href="#" id="logout">Logout<i class="fa fa-sign-out"></i></a></li>
    </ul>
    </li>
    </ul>
    </nav>
    </header>
    </section>
    <script src="js/homeui.js"></script>
    </body>
    </html>


    El marcado es simple. Consta de un header y un nav, con una lista incluída con dos elementos: Messages y un dropdown. El dropdown contiene una lista que son las opciones del usuario logueado.

    CSS

    Primero hacemos todos los elementos border-box:

    Código (css) [Seleccionar]

    html { box-sizing: border-box; }
    *, *:before, *:after { box-sizing: inherit; }


    Preload:

    El preload es un simple etiqueta section con un elemento i dentro, el cual será la animación. Veamos que elementos tiene:

    Código (css) [Seleccionar]

    .preload {
    align-items: center;
    background-color: #F22613;
    display: flex;
    height: 100vh;
    justify-content: center;
    left: 0;
    opacity: 0;
    position: absolute;
    top: 0;
    transition: all .5s ease;
    visibility: hidden;
    width: 100%;
    z-index: 1;
    }
    .preload.visible {
    opacity: 1;
    visibility: visible;
    }
    .preload i {
    color: rgba(255,255,255,.9);
    }


    Como vemos, preload ocupa el 100%(100vh) de alto y ancho, además es de posición absoluta y se posiciona en el vértice izquierdo, lo que junto con sus medidas hace que cubra toda la pantalla. Tiene una opcidad de 0 y una visibilidad oculta (hidden) por defecto, además se comporta como flexbox y tiene un centrado absoluto (flex-align: center y justify-content: center).

    El color del ícono animado es de color blanco con una opacidad de .9 (hace que se note apenas el fondo). La clase que activa la animación, se llama visible y lo único que hace es cambiar la opacidad a 1 y la visibilidad a visible.

    El elemento i es animado con la ayuda de font awesome, pero se puede hacer manualmente, quizás lo veamos en otro tutorial.

    Main

    El main es donde están todos nuestros elementos. Es el container general. Tiene las siguientes propiedades:

    Código (css) [Seleccionar]

    .main {
    opacity: 0;
    transition: all .6s ease;
    visibility: hidden;
    }
    .main.visible {
    opacity: 1;
    visibility: visible;
    }


    Creo que en este punto ya sabemos que significa... Oculto por defecto y cuando se aplica la clase visible, se hace visible con animación. Ahora veamos el header y el nav:

    Código (css) [Seleccionar]

    header {
    background-color: #22A7F0;
    color: rgba(255,255,255,.9);
    display: block;
    }
    .navbar {
    align-items: center;
    color: inherit;
    display: flex;
    justify-content: space-between;
    margin: 0px;
    padding: 0 .5rem;
    width: 100%;
    }


    Ambos tienen un ancho de 100%. El header es block y nav es flex. El nav tiene la propiedad justify-content: space-between, que hace que los hijos de alineen hacia los lados dejando todo el espacio restante del padre entre ellos. ¿Cuáles son los hijos? Son el logo de la empresa y la lista.

    El logo de la empresa tiene la clase brand y tiene los siguientes estilos:

    Código (css) [Seleccionar]

    .brand {
    align-self: stretch;
    align-items: center;
    color: inherit;
    display: flex;
    font-family: 'segoe ui';
    margin: 0px;
    padding: 0 .25rem;
    }
    .brand > i {
    margin-left: .8rem;
    }


    De entrada, podemos ver que el brand tiene la propiedd align-self: stretch. Ésta propiedad sobreescribe el comportamiento por defecto de un hijo flex en fila (por defecto display: flex) en el eje Y. Es decir, si el padre especifica un align-items: center y el hijo especifica align-self, stretch, predomina el comportamiento del hijo. El valor stretch hace que el hijo se estire ocupando todo el alto del padre.

    Veamos la lista y sus elementos:

    Código (css) [Seleccionar]

    .navbar ul {
    display: block;
    list-style: none;
    margin: 0px;
    padding: 0px;
    }
    .navbar > .menu {
    display: block;
    }
    .menu > li {
    display: inline-block;
    transition: all .1s ease-in;
    }
    .menu > li:hover {
    background-color: #1C99DD;
    }


    La lista es un bloque y sus elementos son bloque en línea, lo que hace que se muestre en forma horizontal dentro de la lista. Además, tienen una transición que anima el cambio de fondo cuando se hace hover sobre ellos. Además, ellos tendrán un margen a la derecha de 55px siempre y cuando no sea el último elemento de la lista y sus hijos (elementos a) serán elementos de bloque y tendrán cierto padding:

    Código (css) [Seleccionar]

    .menu > li > a {
    display: block;
    padding: 1rem .5rem;
    }
    .menu > li > a > i {
    margin-left: 10px;
    }
    .menu > li:not(:last-of-type) {
    margin: 0 55px 0 0;
    }


    Veamos ahora, el dropdwon que serán las opciones del usuario.

    Código (css) [Seleccionar]

    /* last li (profile dropdown) */
    .menu > li:last-of-type {
    position: relative;
    }
    /* dropdown */
    .menu > li:last-of-type > ul {
    background-color: #22A7F0;
    border-radius: .1725rem;
    left: -50%;
    opcity: 0;
    padding: .5rem 0;
    position: absolute;
    top: 170%;
    visibility: hidden;
    transition: all .14s ease-in;
    }
    /* arrow of menu */
    .menu > li:last-of-type > ul:after {
    border-color: #22A7F0 transparent;
    border-style: solid;
    border-width: 0 8px 8px 8px;
    content: "";
    position: absolute;
    right: 8px;
    top: -7px;
    }
    .menu > li:last-of-type:hover > ul {
    opacity: 1;
    top: 130%;
    visibility: visible;
    }


    El menú de usuario (dropdown), tendrá una posición relative, lo que permitirá aplicar a su lista interna, una posición absoluta y posicionarla debajo. La lista como ya dijimos tiene posición absoluta, una opacidad de 0, visibilidad oculta (hidden), un left de -50% lo que hará que la lista se desplace a la izquierda y un top de 170% que posiciona la lista muy abajo.

    Cuando se haga hover en el menú de usuario, la lista interna se hace visible (opacidad, visibility) y el top se reduce a 130%, lo que da el efecto de desplazamiento hacia arriba mientras se hace visible.

    Los li y a de la lista interna, ambos son block lo que hace que se muestre en forma de columna. Además, los li tienen se animan en cuanto se haga hover sobre ellos y se cambie el color.

    Código (css) [Seleccionar]

    /* dropdown list items*/
    .menu > li:last-of-type > ul > li, .menu > li:last-of-type > ul a {
    display: block;
    font-size: .9rem;
    transition: transform .1s ease-in;
    }
    /* dropdown options */
    .menu > li:last-of-type > ul a {
    padding: .5rem .9rem;
    width: 8rem;
    }
    /* a elements of dropdown options */
    .menu > li:last-of-type > ul li:hover {
    background-color: #1998DC;
    }
    /* margin left to dropdown icon */
    .menu > li:last-of-type > a > i {
    margin-left: .8rem;
    }
    /* dropdown options icons */
    .menu li:last-of-type > ul a > i {
    float: right;
    margin-top: .3125rem;
    }


    Por último, la sección donde irá el avatar del usuario:

    Código (css) [Seleccionar]

    /* profile image */
    #profile-img {
    display: flex;
    justify-content: center;
    margin-bottom: 5px;
    pointer-events: none;
    width: 100%;
    }
    #profile-img > img {
    background-position: center;
    background-size: cover;
    border-radius: 50%;
    display: block;
    height: 5rem;
    width: 5rem;
    }


    La sección que contiene la imagen del usuario es un bloque tipo flex que ocupa el 100% y que alinea la imagen al centro horizontal (justify-content: center). La imagen tiene un ancho y alto de 5rem (80px) y la imagen estará centrada y ocupara todos los 80px.

    El resultado:


    Código JS:

    Código (javascript) [Seleccionar]

    'use strict';
    window.addEventListener('load', function() {
    let full_access = sessionStorage.getItem('full_access');
    let preload = document.querySelector('.preload');
    let main = document.querySelector('.main');
    // full_access is gived when user enter for first time
    if(full_access == "false") {
    // show preload animation
    preload.classList.add('visible');
    // animation delay 3s. After that, the main content appear
    window.setTimeout(function() {
    preload.classList.remove('visible');
    main.classList.add('visible');
    },3000);
    // change the flag. Now, the user has full access
    sessionStorage.setItem('full_access', true);
    }
    // if user has full_access, just show the page
    else {
    main.classList.add('visible');
    }
    });
    document.addEventListener('DOMContentLoaded', function() {
    document.querySelector('#logout').addEventListener('click', function(e) {
    e.preventDefault();
    // remove user's session
    sessionStorage.removeItem('full_access');
    // redirect to login
    window.location.href = '/PreloadCSS';
    });
    });


    Primero obtenemos el item 'full_access' de la sesión. Como sabemos, en el login, lo inicializamos en false cuando se ha logueado el usuario por primera vez.Seleccionamos el preload y el main y los guardamos en variables locales.

    Verificamos, si full_access es false (lo será la primera vez que se loguee) se le aplica la clase 'visible' al preload, que como recordamos, al aplicarle visible se muestra el preload y su animación.

    Creamos un delay de 3 segundos (el tiempo que tarda la animación) y cuando termine removemos la clase active del preload, haciendo que se oculte y agregamos la clase visible al main, haciendo que éste se haga visible. Al final, cambiamos el valor full_access por true.

    Si ya se tiene acceso total, simplemente se agrega la clase visible al main, haciendolo visible (sin mostrar el preload). Lo anterior lo aplicamos en el evento load de window.

    Por último, cuando el dom esté cargado, escuchamos por evento click en la opción logout del menú de usuario, removiendo la sesión y redirigiendo al login (fíjense que éste tbn tiene un efecto).


    [/code]
#60
Desarrollo Web / Re: Estilos CSS
24 Junio 2015, 22:49 PM
Esa línea la está cuausando otra cosa. Analiza esa línea con las herramientas del navegador y checka qué la causa.