diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f215b69e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +/**/.DS_Store +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/** +!**/src/test/** +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +### VS Code ### +.vscode/ diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..48e760690 --- /dev/null +++ b/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'org.springframework.boot' version '2.1.7.RELEASE' + id 'java' +} + +apply plugin: 'io.spring.dependency-management' + +group = 'com.woowacourse' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '1.8' + +configurations { + developmentOnly + runtimeClasspath { + extendsFrom developmentOnly + } +} + +repositories { + mavenCentral() +} + +test { + useJUnitPlatform() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.mindrot:jbcrypt:0.3m' + developmentOnly 'org.springframework.boot:spring-boot-devtools' + runtimeOnly 'com.h2database:h2' + runtimeOnly 'mysql:mysql-connector-java' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testImplementation('org.springframework.boot:spring-boot-starter-test') { + exclude group: 'junit' + } + testImplementation 'org.springframework.boot:spring-boot-starter-webflux' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' +} + + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..87b738cbd Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..c93c70d8d --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Aug 13 12:28:23 KST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..af6708ff2 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..0f8d5937c --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..27f90497f --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'zzazanstagram' diff --git a/src/main/java/com/woowacourse/zzazanstagram/ZzazanstagramApplication.java b/src/main/java/com/woowacourse/zzazanstagram/ZzazanstagramApplication.java new file mode 100644 index 000000000..0903f02c6 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/ZzazanstagramApplication.java @@ -0,0 +1,13 @@ +package com.woowacourse.zzazanstagram; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ZzazanstagramApplication { + + public static void main(String[] args) { + SpringApplication.run(ZzazanstagramApplication.class, args); + } + +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/config/WebConfig.java b/src/main/java/com/woowacourse/zzazanstagram/config/WebConfig.java new file mode 100644 index 000000000..81ae326b0 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/config/WebConfig.java @@ -0,0 +1,31 @@ +package com.woowacourse.zzazanstagram.config; + +import com.woowacourse.zzazanstagram.web.interceptor.LoginInterceptor; +import com.woowacourse.zzazanstagram.web.resolver.SessionArgumentResolver; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.Arrays; +import java.util.List; + +@Configuration +@EnableJpaAuditing +public class WebConfig implements WebMvcConfigurer { + + private final List excludePatterns = Arrays.asList("/signup", "/members", "/login", "/css/**", "/images/**"); + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new LoginInterceptor()) + .addPathPatterns("/**") + .excludePathPatterns(excludePatterns); + } + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(new SessionArgumentResolver()); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/Article.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/Article.java new file mode 100644 index 000000000..0e9fe37ff --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/Article.java @@ -0,0 +1,47 @@ +package com.woowacourse.zzazanstagram.model.article.domain; + +import com.woowacourse.zzazanstagram.model.article.domain.vo.Contents; +import com.woowacourse.zzazanstagram.model.article.domain.vo.Image; +import com.woowacourse.zzazanstagram.model.common.BaseEntity; +import com.woowacourse.zzazanstagram.model.member.domain.Member; + +import javax.persistence.*; + +@Entity +public class Article extends BaseEntity { + private Image image; + private Contents contents; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "author", nullable = false, foreignKey = @ForeignKey(name = "fk_article_to_member")) + private Member author; + + protected Article() { + } + + public Article(final Image image, final Contents contents, final Member author) { + this.image = image; + this.contents = contents; + this.author = author; + } + + public Image getImage() { + return image; + } + + public Contents getContents() { + return contents; + } + + public String getImageValue() { + return image.getUrl(); + } + + public String getContentsValue() { + return contents.getContents(); + } + + public Member getAuthor() { + return author; + } +} \ No newline at end of file diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/vo/Contents.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/vo/Contents.java new file mode 100644 index 000000000..9a5c851f4 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/vo/Contents.java @@ -0,0 +1,28 @@ +package com.woowacourse.zzazanstagram.model.article.domain.vo; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.Lob; + +@Embeddable +public class Contents { + + @Lob + @Column(name = "contents") + private String contents; + + private Contents() { + } + + private Contents(final String contents) { + this.contents = contents; + } + + public static Contents of(final String contents) { + return new Contents(contents); + } + + public String getContents() { + return contents; + } +} \ No newline at end of file diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/vo/Image.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/vo/Image.java new file mode 100644 index 000000000..b5c2d32ec --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/domain/vo/Image.java @@ -0,0 +1,26 @@ +package com.woowacourse.zzazanstagram.model.article.domain.vo; + +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class Image { + + @Column(name = "image_url", nullable = false) + private String url; + + private Image() { + } + + private Image(final String url) { + this.url = url; + } + + public static Image of(final String imageUrl) { + return new Image(imageUrl); + } + + public String getUrl() { + return url; + } +} \ No newline at end of file diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleRequest.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleRequest.java new file mode 100644 index 000000000..7c028df16 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleRequest.java @@ -0,0 +1,45 @@ +package com.woowacourse.zzazanstagram.model.article.dto; + +import javax.validation.constraints.NotBlank; + +public class ArticleRequest { + + @NotBlank + private String image; + + private String contents; + private String hashTag; + + public ArticleRequest() { + } + + public ArticleRequest(String image, String contents, String hashTag) { + this.image = image; + this.contents = contents; + this.hashTag = hashTag; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public String getContents() { + return contents; + } + + public void setContents(String contents) { + this.contents = contents; + } + + public String getHashTag() { + return hashTag; + } + + public void setHashTag(String hashTag) { + this.hashTag = hashTag; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java new file mode 100644 index 000000000..0975c024d --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java @@ -0,0 +1,115 @@ +package com.woowacourse.zzazanstagram.model.article.dto; + +import java.time.LocalDateTime; + +public class ArticleResponse { + private Long id; + private String image; + private String contents; + // private String hashTag; + private String nickName; + private String profileImage; + private LocalDateTime createdDate; + private LocalDateTime lastModifiedDate; + + //Todo 댓글, 좋아요 추가하자 + + public ArticleResponse() { + } + + private ArticleResponse(Long id, String image, String contents, String nickName, String profileImage, LocalDateTime createdDate, LocalDateTime lastModifiedDate) { + this.id = id; + this.image = image; + this.contents = contents; + this.nickName = nickName; + this.profileImage = profileImage; + this.createdDate = createdDate; + this.lastModifiedDate = lastModifiedDate; + } + + public Long getId() { + return id; + } + + public String getImage() { + return image; + } + + public String getContents() { + return contents; + } + + public String getNickName() { + return nickName; + } + + public String getProfileImage() { + return profileImage; + } + + public LocalDateTime getCreatedDate() { + return createdDate; + } + + public LocalDateTime getLastModifiedDate() { + return lastModifiedDate; + } + + + public static final class ArticleResponseBuilder { + private Long id; + private String image; + private String contents; + // private String hashTag; + private String nickName; + private String profileImage; + private LocalDateTime createdDate; + private LocalDateTime lastModifiedDate; + + private ArticleResponseBuilder() { + } + + public static ArticleResponseBuilder anArticleResponse() { + return new ArticleResponseBuilder(); + } + + public ArticleResponseBuilder id(Long id) { + this.id = id; + return this; + } + + public ArticleResponseBuilder image(String image) { + this.image = image; + return this; + } + + public ArticleResponseBuilder contents(String contents) { + this.contents = contents; + return this; + } + + public ArticleResponseBuilder nickName(String nickName) { + this.nickName = nickName; + return this; + } + + public ArticleResponseBuilder profileImage(String profileImage) { + this.profileImage = profileImage; + return this; + } + + public ArticleResponseBuilder createdDate(LocalDateTime createdDate) { + this.createdDate = createdDate; + return this; + } + + public ArticleResponseBuilder lastModifiedDate(LocalDateTime lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + return this; + } + + public ArticleResponse build() { + return new ArticleResponse(id, image, contents, nickName, profileImage, createdDate, lastModifiedDate); + } + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/exception/ArticleException.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/exception/ArticleException.java new file mode 100644 index 000000000..d9cfb3310 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/exception/ArticleException.java @@ -0,0 +1,10 @@ +package com.woowacourse.zzazanstagram.model.article.exception; + +public class ArticleException extends IllegalArgumentException { + public ArticleException() { + } + + public ArticleException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/repository/ArticleRepository.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/repository/ArticleRepository.java new file mode 100644 index 000000000..52258ce1c --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/repository/ArticleRepository.java @@ -0,0 +1,12 @@ +package com.woowacourse.zzazanstagram.model.article.repository; + +import com.woowacourse.zzazanstagram.model.article.domain.Article; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ArticleRepository extends JpaRepository { + List
findAllByOrderByIdDesc(); +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/service/ArticleAssembler.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/service/ArticleAssembler.java new file mode 100644 index 000000000..e86e97cc4 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/service/ArticleAssembler.java @@ -0,0 +1,35 @@ +package com.woowacourse.zzazanstagram.model.article.service; + +import com.woowacourse.zzazanstagram.model.article.domain.Article; +import com.woowacourse.zzazanstagram.model.article.domain.vo.Contents; +import com.woowacourse.zzazanstagram.model.article.domain.vo.Image; +import com.woowacourse.zzazanstagram.model.article.dto.ArticleRequest; +import com.woowacourse.zzazanstagram.model.article.dto.ArticleResponse; +import com.woowacourse.zzazanstagram.model.member.domain.Member; + +import java.time.LocalDateTime; + +public class ArticleAssembler { + public static Article toEntity(ArticleRequest dto, Member author) { + Image image = Image.of(dto.getImage()); + Contents contents = Contents.of(dto.getContents()); + + return new Article(image, contents, author); + } + + public static ArticleResponse toDto(Article article) { + Long id = article.getId(); + LocalDateTime createdDate = article.getCreatedDate(); + LocalDateTime lastModifiedDate = article.getLastModifiedDate(); + + return ArticleResponse.ArticleResponseBuilder.anArticleResponse() + .id(id) + .image(article.getImageValue()) + .contents(article.getContentsValue()) + .nickName(article.getAuthor().getNickNameValue()) + .profileImage(article.getAuthor().getProfileImageValue()) + .createdDate(createdDate) + .lastModifiedDate(lastModifiedDate) + .build(); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/service/ArticleService.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/service/ArticleService.java new file mode 100644 index 000000000..1cb62c50e --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/service/ArticleService.java @@ -0,0 +1,45 @@ +package com.woowacourse.zzazanstagram.model.article.service; + +import com.woowacourse.zzazanstagram.model.article.domain.Article; +import com.woowacourse.zzazanstagram.model.article.dto.ArticleRequest; +import com.woowacourse.zzazanstagram.model.article.dto.ArticleResponse; +import com.woowacourse.zzazanstagram.model.article.repository.ArticleRepository; +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.service.MemberService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ArticleService { + private static final Logger log = LoggerFactory.getLogger(ArticleService.class); + private static final String TAG = "[ArticleService]"; + + private final ArticleRepository articleRepository; + private final MemberService memberService; + + public ArticleService(ArticleRepository articleRepository, MemberService memberService) { + this.articleRepository = articleRepository; + this.memberService = memberService; + } + + public List getArticleResponses() { + List
articles = articleRepository.findAllByOrderByIdDesc(); + + return articles.stream() + .map(ArticleAssembler::toDto) + .collect(Collectors.toList()); + } + + public void save(ArticleRequest dto, String email) { + Member author = memberService.findMemberByEmail(email); + + Article article = ArticleAssembler.toEntity(dto, author); + articleRepository.save(article); + + log.info("{} create() >> {}", TAG, article); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/common/BaseEntity.java b/src/main/java/com/woowacourse/zzazanstagram/model/common/BaseEntity.java new file mode 100644 index 000000000..4d87c6367 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/common/BaseEntity.java @@ -0,0 +1,48 @@ +package com.woowacourse.zzazanstagram.model.common; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.*; +import java.time.LocalDateTime; +import java.util.Objects; + +@MappedSuperclass +@EntityListeners(value = AuditingEntityListener.class) +public abstract class BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @CreatedDate + private LocalDateTime createdDate; + + @LastModifiedDate + private LocalDateTime lastModifiedDate; + + public Long getId() { + return id; + } + + public LocalDateTime getCreatedDate() { + return createdDate; + } + + public LocalDateTime getLastModifiedDate() { + return lastModifiedDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BaseEntity that = (BaseEntity) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/MemberSession.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/MemberSession.java new file mode 100644 index 000000000..ed9f265cb --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/MemberSession.java @@ -0,0 +1,39 @@ +package com.woowacourse.zzazanstagram.model.member; + +import java.io.Serializable; + +public class MemberSession implements Serializable { + private String email; + private String nickName; + private String profileImage; + + public MemberSession(String email, String nickName, String profileImage) { + this.email = email; + this.nickName = nickName; + this.profileImage = profileImage; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getProfileImage() { + return profileImage; + } + + public void setProfileImage(String profileImage) { + this.profileImage = profileImage; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java new file mode 100644 index 000000000..caa034bfe --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java @@ -0,0 +1,108 @@ +package com.woowacourse.zzazanstagram.model.member.domain; + +import com.woowacourse.zzazanstagram.model.common.BaseEntity; +import com.woowacourse.zzazanstagram.model.member.domain.vo.*; + +import javax.persistence.Entity; + +@Entity +public class Member extends BaseEntity { + private NickName nickName; + private Name name; + private Email email; + private Password password; + private ProfileImage profileImage; + + protected Member() { + } + + public boolean isMatchPassword(String password) { + return this.password.isMatch(password); + } + + public NickName getNickName() { + return nickName; + } + + public Name getName() { + return name; + } + + public Email getEmail() { + return email; + } + + public Password getPassword() { + return password; + } + + public ProfileImage getProfileImage() { + return profileImage; + } + + public String getNameValue() { + return name.getName(); + } + + public String getEmailValue() { + return email.getEmail(); + } + + public String getNickNameValue() { + return nickName.getNickName(); + } + + public String getProfileImageValue() { + return profileImage.getUrl(); + } + + public static final class MemberBuilder { + private NickName nickName; + private Name name; + private Email email; + private Password password; + private ProfileImage profileImage; + + private MemberBuilder() { + } + + public static MemberBuilder aMember() { + return new MemberBuilder(); + } + + public MemberBuilder nickName(String nickName) { + this.nickName = NickName.of(nickName); + return this; + } + + public MemberBuilder name(String name) { + this.name = Name.of(name); + return this; + } + + public MemberBuilder email(String email) { + this.email = Email.of(email); + return this; + } + + public MemberBuilder password(String password) { + this.password = Password.of(password); + return this; + } + + public MemberBuilder profile(String profile) { + this.profileImage = ProfileImage.of(profile); + return this; + } + + public Member build() { + Member member = new Member(); + member.name = this.name; + member.nickName = this.nickName; + member.email = this.email; + member.password = this.password; + member.profileImage = this.profileImage; + return member; + } + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java new file mode 100644 index 000000000..aab7e5256 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java @@ -0,0 +1,40 @@ +package com.woowacourse.zzazanstagram.model.member.domain.vo; + +import com.woowacourse.zzazanstagram.model.member.exception.MemberEmailFormatException; + +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class Email { + private static final String EMAIL_REGEX = "^[_a-zA-Z0-9-.]+@[.a-zA-Z0-9-]+\\.[a-zA-Z]+$"; + + @Column(name = "email", unique = true) + private String email; + + private Email(final String email) { + this.email = validate(email); + } + + private Email() { + } + + public static Email of(final String email) { + return new Email(email); + } + + private String validate(final String email) { + if (isMismatch(email)) { + throw new MemberEmailFormatException("잘못된 형식의 이메일입니다."); + } + return email; + } + + private boolean isMismatch(String email) { + return !email.matches(EMAIL_REGEX); + } + + public String getEmail() { + return email; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java new file mode 100644 index 000000000..93e3bbbb7 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java @@ -0,0 +1,40 @@ +package com.woowacourse.zzazanstagram.model.member.domain.vo; + +import com.woowacourse.zzazanstagram.model.member.exception.MemberNameFormatException; + +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class Name { + private static final String NAME_REGEX = "[A-Za-zㄱ-ㅎㅏ-ㅣ가-힣]{2,10}"; + + @Column(name = "name") + private String name; + + private Name(final String name) { + this.name = validate(name); + } + + private Name() { + } + + public static Name of(final String name) { + return new Name(name); + } + + private String validate(final String name) { + if (isMismatch(name)) { + throw new MemberNameFormatException("이름은 2자 이상 10자 이하입니다."); + } + return name; + } + + private boolean isMismatch(String name) { + return !name.matches(NAME_REGEX); + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java new file mode 100644 index 000000000..aaa5a26f1 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java @@ -0,0 +1,40 @@ +package com.woowacourse.zzazanstagram.model.member.domain.vo; + +import com.woowacourse.zzazanstagram.model.member.exception.MemberNickNameFormatException; + +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class NickName { + private static final String NICK_NAME_REGEX = "[0-9A-Za-zㄱ-ㅎㅏ-ㅣ가-힣]{2,10}"; + + @Column(name = "nick_name", unique = true) + private String nickName; + + private NickName(final String name) { + this.nickName = validate(name); + } + + private NickName() { + } + + public static NickName of(final String name) { + return new NickName(name); + } + + private String validate(final String name) { + if (isMismatch(name)) { + throw new MemberNickNameFormatException("이름은 2자 이상 10자 이하입니다."); + } + return name; + } + + private boolean isMismatch(String name) { + return !name.matches(NICK_NAME_REGEX); + } + + public String getNickName() { + return nickName; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java new file mode 100644 index 000000000..542b0bf44 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java @@ -0,0 +1,59 @@ +package com.woowacourse.zzazanstagram.model.member.domain.vo; + +import com.woowacourse.zzazanstagram.model.member.exception.MemberPasswordFormatException; +import org.mindrot.jbcrypt.BCrypt; + +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class Password { + private static final String PASSWORD_REGEX = ".*(?=^.{8,}$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&+=]).*"; + + @Column(name = "password") + private String password; + + private Password(final String password) { + this.password = validate(password); + } + + private Password() { + } + + public static Password of(final String password) { + return new Password(password); + } + + private String validate(final String password) { + if (isMismatch(password)) { + throw new MemberPasswordFormatException("잘못된 형식의 비밀번호입니다."); + } + return encrypt(password); + } + + private boolean isMismatch(String password) { + return !password.matches(PASSWORD_REGEX); + } + + private String encrypt(String password) { + return Encrypt.encrypt(password); + } + + public boolean isMatch(String password) { + return Encrypt.isMatch(password, this.password); + } + + public String getPassword() { + return password; + } + + private static class Encrypt { + static String encrypt(String password) { + return BCrypt.hashpw(password, BCrypt.gensalt()); + } + + static boolean isMatch(String password, String hashed) { + return BCrypt.checkpw(password, hashed); + } + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java new file mode 100644 index 000000000..5c8b7fc10 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java @@ -0,0 +1,26 @@ +package com.woowacourse.zzazanstagram.model.member.domain.vo; + +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class ProfileImage { + + @Column(name = "profile_image_url") + private String url; + + private ProfileImage(final String url) { + this.url = url; + } + + private ProfileImage() { + } + + public static ProfileImage of(final String url) { + return new ProfileImage(url); + } + + public String getUrl() { + return url; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberLoginRequest.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberLoginRequest.java new file mode 100644 index 000000000..01b4c9f3a --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberLoginRequest.java @@ -0,0 +1,27 @@ +package com.woowacourse.zzazanstagram.model.member.dto; + +public class MemberLoginRequest { + private String email; + private String password; + + public MemberLoginRequest(String email, String password) { + this.email = email; + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java new file mode 100644 index 000000000..28396f266 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java @@ -0,0 +1,47 @@ +package com.woowacourse.zzazanstagram.model.member.dto; + +public class MemberResponse { + private String nickName; + private String name; + private String email; + private String profileImage; + + public MemberResponse(String nickName, String name, String email, String profileImage) { + this.nickName = nickName; + this.name = name; + this.email = email; + this.profileImage = profileImage; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getProfileImage() { + return profileImage; + } + + public void setProfileImage(String profileImage) { + this.profileImage = profileImage; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberSignUpRequest.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberSignUpRequest.java new file mode 100644 index 000000000..76e019c95 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberSignUpRequest.java @@ -0,0 +1,64 @@ +package com.woowacourse.zzazanstagram.model.member.dto; + +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + +public class MemberSignUpRequest { + @NotBlank + private String name; + + @NotBlank + @Email + private String email; + + @NotBlank + private String nickName; + + @NotBlank + private String password; + + @URL + private String profile; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberEmailFormatException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberEmailFormatException.java new file mode 100644 index 000000000..ae7caae7f --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberEmailFormatException.java @@ -0,0 +1,11 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberEmailFormatException extends MemberException { + public MemberEmailFormatException() { + super(); + } + + public MemberEmailFormatException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberException.java new file mode 100644 index 000000000..b97ade84e --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberException.java @@ -0,0 +1,10 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberException extends IllegalArgumentException { + public MemberException() { + } + + public MemberException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberLoginFailException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberLoginFailException.java new file mode 100644 index 000000000..6ba7ccc63 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberLoginFailException.java @@ -0,0 +1,11 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberLoginFailException extends MemberException { + public MemberLoginFailException() { + super(); + } + + public MemberLoginFailException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNameFormatException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNameFormatException.java new file mode 100644 index 000000000..fa0b0054a --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNameFormatException.java @@ -0,0 +1,11 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberNameFormatException extends MemberException { + public MemberNameFormatException() { + super(); + } + + public MemberNameFormatException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNickNameFormatException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNickNameFormatException.java new file mode 100644 index 000000000..5c7014d87 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNickNameFormatException.java @@ -0,0 +1,11 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberNickNameFormatException extends MemberException { + public MemberNickNameFormatException() { + super(); + } + + public MemberNickNameFormatException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNotFoundException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNotFoundException.java new file mode 100644 index 000000000..5e6d8174a --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberNotFoundException.java @@ -0,0 +1,10 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberNotFoundException extends MemberException { + public MemberNotFoundException() { + } + + public MemberNotFoundException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberPasswordFormatException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberPasswordFormatException.java new file mode 100644 index 000000000..c8e606624 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberPasswordFormatException.java @@ -0,0 +1,11 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberPasswordFormatException extends MemberException { + public MemberPasswordFormatException() { + super(); + } + + public MemberPasswordFormatException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberProfileUrlFormatException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberProfileUrlFormatException.java new file mode 100644 index 000000000..d4fbdedc6 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberProfileUrlFormatException.java @@ -0,0 +1,11 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberProfileUrlFormatException extends MemberException { + public MemberProfileUrlFormatException() { + super(); + } + + public MemberProfileUrlFormatException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberSaveException.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberSaveException.java new file mode 100644 index 000000000..431d21b88 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/exception/MemberSaveException.java @@ -0,0 +1,10 @@ +package com.woowacourse.zzazanstagram.model.member.exception; + +public class MemberSaveException extends MemberException { + public MemberSaveException() { + } + + public MemberSaveException(String s) { + super(s); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/repository/MemberRepository.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/repository/MemberRepository.java new file mode 100644 index 000000000..9595feb6a --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/repository/MemberRepository.java @@ -0,0 +1,16 @@ +package com.woowacourse.zzazanstagram.model.member.repository; + +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.domain.vo.Email; +import com.woowacourse.zzazanstagram.model.member.domain.vo.NickName; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface MemberRepository extends JpaRepository { + Optional findByEmail(Email email); + + Optional findByNickName(NickName nickName); + + boolean existsByNickNameOrEmail(NickName nickName, Email email); +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/service/LoginService.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/service/LoginService.java new file mode 100644 index 000000000..4342421c6 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/service/LoginService.java @@ -0,0 +1,36 @@ +package com.woowacourse.zzazanstagram.model.member.service; + +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.domain.vo.Email; +import com.woowacourse.zzazanstagram.model.member.dto.MemberLoginRequest; +import com.woowacourse.zzazanstagram.model.member.dto.MemberResponse; +import com.woowacourse.zzazanstagram.model.member.exception.MemberLoginFailException; +import com.woowacourse.zzazanstagram.model.member.repository.MemberRepository; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class LoginService { + private static final String ERROR_ILLEGAL_LOGIN_MESSAGE = "로그인 정보가 올바르지 않습니다."; + private final MemberRepository memberRepository; + + public LoginService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + public MemberResponse find(MemberLoginRequest request) { + Member member = checkEnrolledMember(request); + return MemberAssembler.assemble(member); + } + + private Member checkEnrolledMember(MemberLoginRequest request) { + return findByEmail(request.getEmail()) + .filter(m -> m.isMatchPassword(request.getPassword())) + .orElseThrow(() -> new MemberLoginFailException(ERROR_ILLEGAL_LOGIN_MESSAGE)); + } + + private Optional findByEmail(String email) { + return memberRepository.findByEmail(Email.of(email)); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/service/MemberAssembler.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/service/MemberAssembler.java new file mode 100644 index 000000000..a1adc4ad7 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/service/MemberAssembler.java @@ -0,0 +1,20 @@ +package com.woowacourse.zzazanstagram.model.member.service; + +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.dto.MemberResponse; +import com.woowacourse.zzazanstagram.model.member.dto.MemberSignUpRequest; + +public class MemberAssembler { + static MemberResponse assemble(Member member) { + return new MemberResponse(member.getNickNameValue(), member.getNameValue(), member.getEmailValue(), member.getProfileImageValue()); + } + + static Member toEntity(MemberSignUpRequest memberSignupRequest) { + return Member.MemberBuilder.aMember().email(memberSignupRequest.getEmail()) + .name(memberSignupRequest.getName()) + .nickName(memberSignupRequest.getNickName()) + .password(memberSignupRequest.getPassword()) + .profile(memberSignupRequest.getProfile()) + .build(); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/service/MemberService.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/service/MemberService.java new file mode 100644 index 000000000..acda437cb --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/service/MemberService.java @@ -0,0 +1,38 @@ +package com.woowacourse.zzazanstagram.model.member.service; + +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.domain.vo.Email; +import com.woowacourse.zzazanstagram.model.member.domain.vo.NickName; +import com.woowacourse.zzazanstagram.model.member.dto.MemberSignUpRequest; +import com.woowacourse.zzazanstagram.model.member.exception.MemberNotFoundException; +import com.woowacourse.zzazanstagram.model.member.exception.MemberSaveException; +import com.woowacourse.zzazanstagram.model.member.repository.MemberRepository; +import org.springframework.stereotype.Service; + +@Service +public class MemberService { + private MemberRepository memberRepository; + + public MemberService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + public Member findMemberByEmail(String email) { + return memberRepository.findByEmail(Email.of(email)) + .orElseThrow(() -> new MemberNotFoundException("잘못된 접근입니다.")); + } + + public void save(MemberSignUpRequest memberSignupRequest) { + if (checkEnrolledEmailOrNickName(memberSignupRequest)) { + throw new MemberSaveException("이미 존재하는 이메일 또는 닉네임 입니다."); + } + Member member = MemberAssembler.toEntity(memberSignupRequest); + memberRepository.save(member); + } + + private boolean checkEnrolledEmailOrNickName(MemberSignUpRequest memberSignupRequest) { + NickName nickName = NickName.of(memberSignupRequest.getNickName()); + Email email = Email.of(memberSignupRequest.getEmail()); + return memberRepository.existsByNickNameOrEmail(nickName, email); + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/SessionKeys.java b/src/main/java/com/woowacourse/zzazanstagram/web/SessionKeys.java new file mode 100644 index 000000000..40811a3e7 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/SessionKeys.java @@ -0,0 +1,8 @@ +package com.woowacourse.zzazanstagram.web; + +public class SessionKeys { + public static final String MEMBER = "member"; + + private SessionKeys() { + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/controller/article/ArticleController.java b/src/main/java/com/woowacourse/zzazanstagram/web/controller/article/ArticleController.java new file mode 100644 index 000000000..6924ede76 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/controller/article/ArticleController.java @@ -0,0 +1,42 @@ +package com.woowacourse.zzazanstagram.web.controller.article; + +import com.woowacourse.zzazanstagram.model.article.dto.ArticleRequest; +import com.woowacourse.zzazanstagram.model.article.service.ArticleService; +import com.woowacourse.zzazanstagram.model.member.MemberSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +import javax.validation.Valid; + +@Controller +public class ArticleController { + private static final Logger log = LoggerFactory.getLogger(ArticleController.class); + private static final String TAG = "[ArticleController]"; + + private ArticleService articleService; + + public ArticleController(ArticleService articleService) { + this.articleService = articleService; + } + + @GetMapping("/") + public String index(Model model) { + model.addAttribute("articles", articleService.getArticleResponses()); + return "index"; + } + + @GetMapping("/articles/new") + public String createArticle() { + return "article-edit"; + } + + @PostMapping("/articles") + public String create(@Valid ArticleRequest dto, MemberSession memberSession) { + articleService.save(dto, memberSession.getEmail()); + return "redirect:/"; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/LoginController.java b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/LoginController.java new file mode 100644 index 000000000..e0952eab2 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/LoginController.java @@ -0,0 +1,36 @@ +package com.woowacourse.zzazanstagram.web.controller.member; + +import com.woowacourse.zzazanstagram.model.member.MemberSession; +import com.woowacourse.zzazanstagram.model.member.dto.MemberLoginRequest; +import com.woowacourse.zzazanstagram.model.member.dto.MemberResponse; +import com.woowacourse.zzazanstagram.model.member.service.LoginService; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpSession; + +import static com.woowacourse.zzazanstagram.web.SessionKeys.MEMBER; + +@Controller +@RequestMapping("/login") +public class LoginController { + private final LoginService loginService; + + public LoginController(LoginService loginService) { + this.loginService = loginService; + } + + @GetMapping + public String loginForm() { + return "login"; + } + + @PostMapping + public String login(MemberLoginRequest memberLoginRequest, HttpSession httpSession) { + MemberResponse memberResponse = loginService.find(memberLoginRequest); + httpSession.setAttribute(MEMBER, new MemberSession(memberResponse.getEmail(), memberResponse.getNickName(), memberResponse.getProfileImage())); + return "redirect:/"; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/LoginControllerAdvice.java b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/LoginControllerAdvice.java new file mode 100644 index 000000000..633aeec82 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/LoginControllerAdvice.java @@ -0,0 +1,30 @@ +package com.woowacourse.zzazanstagram.web.controller.member; + +import com.woowacourse.zzazanstagram.model.member.exception.MemberLoginFailException; +import com.woowacourse.zzazanstagram.model.member.exception.MemberNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice(assignableTypes = LoginController.class) +public class LoginControllerAdvice { + private static final Logger log = LoggerFactory.getLogger(LoginControllerAdvice.class); + private static final String TAG = "[LoginControllerAdvice]"; + + @ExceptionHandler(MemberLoginFailException.class) + public String handleMemberLoginFailException(MemberLoginFailException e) { + log.error("{} MemberLoginFailException >> {}", TAG, e.getMessage()); + + return "redirect:/login"; + } + + @ExceptionHandler(MemberNotFoundException.class) + public String handleMemberNotFoundException(MemberNotFoundException e) { + log.error("{} MemberNotFoundException >> {}", TAG, e.getMessage()); + + return "redirect:/login"; + } + + +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/MemberController.java b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/MemberController.java new file mode 100644 index 000000000..c1c4282e5 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/MemberController.java @@ -0,0 +1,29 @@ +package com.woowacourse.zzazanstagram.web.controller.member; + +import com.woowacourse.zzazanstagram.model.member.dto.MemberSignUpRequest; +import com.woowacourse.zzazanstagram.model.member.service.MemberService; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +import javax.validation.Valid; + +@Controller +public class MemberController { + private MemberService memberService; + + public MemberController(MemberService memberService) { + this.memberService = memberService; + } + + @GetMapping("/signup") + public String signUp() { + return "signup"; + } + + @PostMapping("/members") + public String saveMember(@Valid MemberSignUpRequest memberSignupRequest) { + memberService.save(memberSignupRequest); + return "redirect:/login"; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/MemberControllerAdvice.java b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/MemberControllerAdvice.java new file mode 100644 index 000000000..3ef0eff3d --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/controller/member/MemberControllerAdvice.java @@ -0,0 +1,55 @@ +package com.woowacourse.zzazanstagram.web.controller.member; + +import com.woowacourse.zzazanstagram.model.member.exception.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice(assignableTypes = MemberController.class) +public class MemberControllerAdvice { + private static final Logger log = LoggerFactory.getLogger(MemberControllerAdvice.class); + private static final String TAG = "[MemberControllerAdvice]"; + + @ExceptionHandler(MemberEmailFormatException.class) + public String handleMemberEmailFormatException(MemberEmailFormatException e) { + log.error("{} MemberEmailFormatException >> {}", TAG, e.getMessage()); + + return "redirect:/signup"; + } + + @ExceptionHandler(MemberNameFormatException.class) + public String handleMemberNameFormatException(MemberNameFormatException e) { + log.error("{} MemberNameFormatException >> {}", TAG, e.getMessage()); + + return "redirect:/signup"; + } + + @ExceptionHandler(MemberNickNameFormatException.class) + public String handleMemberNickNameFormatException(MemberNickNameFormatException e) { + log.error("{} MemberNickNameFormatException >> {}", TAG, e.getMessage()); + + return "redirect:/signup"; + } + + @ExceptionHandler(MemberPasswordFormatException.class) + public String handleMemberPasswordFormatException(MemberPasswordFormatException e) { + log.error("{} MemberPasswordFormatException >> {}", TAG, e.getMessage()); + + return "redirect:/signup"; + } + + @ExceptionHandler(MemberProfileUrlFormatException.class) + public String handleMemberProfileUrlFormatException(MemberProfileUrlFormatException e) { + log.error("{} MemberPasswordFormatException >> {}", TAG, e.getMessage()); + + return "redirect:/signup"; + } + + @ExceptionHandler(MemberSaveException.class) + public String handleMemberSaveException(MemberSaveException e) { + log.error("{} MemberSaveException >> {}", TAG, e.getMessage()); + + return "redirect:/signup"; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/interceptor/LoginInterceptor.java b/src/main/java/com/woowacourse/zzazanstagram/web/interceptor/LoginInterceptor.java new file mode 100644 index 000000000..b944f7eaa --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/interceptor/LoginInterceptor.java @@ -0,0 +1,23 @@ +package com.woowacourse.zzazanstagram.web.interceptor; + +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import static com.woowacourse.zzazanstagram.web.SessionKeys.MEMBER; + +public class LoginInterceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + HttpSession httpSession = request.getSession(); + + if (httpSession.getAttribute(MEMBER) == null) { + response.sendRedirect("/signup"); + return false; + } + + return true; + } +} diff --git a/src/main/java/com/woowacourse/zzazanstagram/web/resolver/SessionArgumentResolver.java b/src/main/java/com/woowacourse/zzazanstagram/web/resolver/SessionArgumentResolver.java new file mode 100644 index 000000000..c52a376c7 --- /dev/null +++ b/src/main/java/com/woowacourse/zzazanstagram/web/resolver/SessionArgumentResolver.java @@ -0,0 +1,25 @@ +package com.woowacourse.zzazanstagram.web.resolver; + +import com.woowacourse.zzazanstagram.model.member.MemberSession; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; + +import static com.woowacourse.zzazanstagram.web.SessionKeys.MEMBER; + +public class SessionArgumentResolver implements HandlerMethodArgumentResolver { + @Override + public boolean supportsParameter(MethodParameter parameter) { + return MemberSession.class.isAssignableFrom(parameter.getParameterType()); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + return request.getSession().getAttribute(MEMBER); + } +} diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties new file mode 100644 index 000000000..d7896f09f --- /dev/null +++ b/src/main/resources/application-test.properties @@ -0,0 +1,13 @@ +spring.devtools.restart.enabled=true +spring.devtools.livereload.enabled=true + +# H2 Setting +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.username=sa +spring.datasource.password= +spring.h2.console.enabled=true +spring.h2.console.path=/console +spring.jpa.hibernate.ddl-auto=create +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 000000000..82ba71c2d --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,20 @@ +spring.devtools.restart.enabled=false +spring.devtools.livereload.enabled=true + +# DataSource +# 플랫폼을 명시하지 않으면 외래키가 먹히지 않음 +#spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +#spring.datasource.url=jdbc:mysql://localhost:3306/blog?autoReconnect=true&useSSL=false +#spring.datasource.username=root +#spring.datasource.password=password + +# H2 Setting +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.username=sa +spring.datasource.password= +spring.h2.console.enabled=true +spring.h2.console.path=/console +spring.jpa.hibernate.ddl-auto=create +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true diff --git a/src/main/resources/static/css/app.css b/src/main/resources/static/css/app.css new file mode 100644 index 000000000..1b3270a26 --- /dev/null +++ b/src/main/resources/static/css/app.css @@ -0,0 +1,1653 @@ +@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700|Roboto:300,400,500,700); +@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700|Roboto:300,400,500,700); +@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700|Roboto:300,400,500,700); +@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700|Roboto:300,400,500,700); +@import url(https://fonts.googleapis.com/earlyaccess/nanumgothic.css); +@import url(https://fonts.googleapis.com/earlyaccess/nanumgothiccoding.css); +@import url(https://fonts.googleapis.com/earlyaccess/nanummyeongjo.css); +@import url(https://fonts.googleapis.com/earlyaccess/nanumbrushscript.css); +@import url(https://fonts.googleapis.com/earlyaccess/nanumpenscript.css); +@import url(https://cdn.jsdelivr.net/font-nanum/1.0/nanumbarungothic/nanumbarungothic.css); +@import url(https://cdn.jsdelivr.net/font-nanum/1.0/nanumbarungothic/nanumbarungothic.css); + +body,html,html a{-webkit-font-smoothing:antialiased} +body,html{height:100%} +body{font-size:14px;background-color:#f6f7fb;color:#333;letter-spacing:.2px;overflow-x:hidden} +body,h1,h2,h3,h4,h5,h6{ + font-family: '나눔고딕','Nanum Gothic','Malgun Gothic','맑은고딕','Apple SD Gothic Neo', Roboto, -apple-system,NanumGothic, + Dotum,'돋움',sans-serif,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif; + line-height:1.5 +} +h1,h2,h3,h4,h5,h6{color:#333;letter-spacing:.5px;font-weight:400} +h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{ + font-family: '나눔고딕','Nanum Gothic','Malgun Gothic','맑은고딕','Apple SD Gothic Neo', Roboto, -apple-system,NanumGothic, + Dotum,'돋움',sans-serif,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif; +} +h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:300;color:#5c5f73} + +h1{font-size:26px} +h2{font-size:22px} +h3{font-size:20px} +h4{font-size:18px} +h5{font-size:16px} +h6{font-size:12px} + +p{ + font-family: '나눔고딕','Nanum Gothic','Malgun Gothic','맑은고딕','Apple SD Gothic Neo', Roboto, -apple-system,NanumGothic, + Dotum,'돋움',sans-serif,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif; + line-height:1.9 +} + +ul{margin-bottom:0} +a{color:#0f9aee} +a:focus,a:hover{text-decoration:none;color:#0c7bbe} +a:focus{outline:none} +a.text-gray.active,a.text-gray:focus,a.text-gray:hover{color:#8f92a1!important} +:focus{outline:none} +hr{border-top:1px solid #e6ecf5} + +.text-link:focus,.text-link:hover{text-decoration:underline} +.text-opacity{opacity:.85} +.text-white{color:#fff!important} +.text-dark{color:#333!important} +.text-gray{color:#8f92a1!important} +.text-primary{color:#7774e7!important} +.text-success{color:#37c936!important} +.text-info{color:#0f9aee!important} +.text-warning{color:#fc0!important} +.text-danger{color:#ff3c7e!important} + +.bg-white{background-color:#fff!important} +.bg-dark{background-color:#333!important} +.bg-gray{background-color:#ebeef6!important} +.bg-primary{background-color:#7774e7!important} +.bg-info{background-color:#0f9aee!important} +.bg-success{background-color:#37c936!important} +.bg-warning{background-color:#fc0!important} +.bg-danger{background-color:#ff3c7e!important} +.bg-primary-inverse{background:#7774e7;background:rgba(119,116,231,.1)} +.bg-success-inverse{background:#37c936;background:rgba(55,201,54,.1)} +.bg-info-inverse{background:#0f9aee;background:rgba(15,154,238,.1)} +.bg-warning-inverse{background:#fc0;background:rgba(255,204,0,.1)} +.bg-danger-inverse{background:#ff3c7e;background:rgba(255,60,126,.1)} +.bg{background-repeat:no-repeat;background-size:cover;background-position:50%} +.overlay-dark{position:relative;overflow:hidden;color:#ccc} +.overlay-dark h1,.overlay-dark h2,.overlay-dark h3,.overlay-dark h4,.overlay-dark h5,.overlay-dark h6{color:#fff} +.overlay-dark p{color:#ccc}.overlay-dark:before{content:"";background-color:#333;position:absolute;width:100%;height:100%;opacity:.5;top:0;left:0;z-index:2} +.overlay-dark>div{position:relative;z-index:3}blockquote{border-left:0;padding-left:30px;position:relative} +blockquote:before{font-family:themify;content:"\E67F";position:absolute;left:0;color:#333} + +.fade.in{opacity:1}.collapse.in{display:block} + +.no-mrg{margin:0!important} +.no-mrg-top{margin-top:0!important} +.no-mrg-btm{margin-bottom:0!important} +.no-mrg-right{margin-right:0!important} +.no-mrg-left{margin-left:0!important} +.no-mrg-vertical{margin-top:0!important;margin-bottom:0!important} +.no-mrg-horizon{margin-left:0!important;margin-right:0!important} +.margin-5{margin:5px!important} +.margin-10{margin:10px!important} +.margin-15{margin:15px!important} +.margin-20{margin:20px!important} +.margin-25{margin:25px!important} +.margin-30{margin:30px!important} +.margin-35{margin:35px!important} +.margin-40{margin:40px!important} +.margin-45{margin:45px!important} +.margin-50{margin:50px!important} +.margin-55{margin:55px!important} +.margin-60{margin:60px!important} +.margin-65{margin:65px!important} +.margin-70{margin:70px!important} +.margin-75{margin:75px!important} +.margin-80{margin:80px!important} +.margin-85{margin:85px!important} +.margin-90{margin:90px!important} +.margin-95{margin:95px!important} +.margin-100{margin:100px!important} +.margin-105{margin:105px!important} +.margin-110{margin:110px!important} +.margin-115{margin:115px!important} +.margin-120{margin:120px!important} +.margin-125{margin:125px!important} +.margin-130{margin:130px!important} +.margin-135{margin:135px!important} +.margin-140{margin:140px!important} +.margin-145{margin:145px!important} +.margin-150{margin:150px!important} + +.mrg-horizon-auto{margin-right:auto!important} +.mrg-horizon-auto,.mrg-left-auto{margin-left:auto!important} +.mrg-right-auto{margin-right:auto!important} +.mrg-vertical-5{margin-top:5px!important;margin-bottom:5px!important} +.mrg-vertical-10{margin-top:10px!important;margin-bottom:10px!important} +.mrg-vertical-15{margin-top:15px!important;margin-bottom:15px!important} +.mrg-vertical-20{margin-top:20px!important;margin-bottom:20px!important} +.mrg-vertical-25{margin-top:25px!important;margin-bottom:25px!important} +.mrg-vertical-30{margin-top:30px!important;margin-bottom:30px!important} +.mrg-vertical-35{margin-top:35px!important;margin-bottom:35px!important} +.mrg-vertical-40{margin-top:40px!important;margin-bottom:40px!important} +.mrg-vertical-45{margin-top:45px!important;margin-bottom:45px!important} +.mrg-vertical-50{margin-top:50px!important;margin-bottom:50px!important} +.mrg-vertical-55{margin-top:55px!important;margin-bottom:55px!important} +.mrg-vertical-60{margin-top:60px!important;margin-bottom:60px!important} +.mrg-vertical-65{margin-top:65px!important;margin-bottom:65px!important} +.mrg-vertical-70{margin-top:70px!important;margin-bottom:70px!important} +.mrg-vertical-75{margin-top:75px!important;margin-bottom:75px!important} +.mrg-vertical-80{margin-top:80px!important;margin-bottom:80px!important} +.mrg-vertical-85{margin-top:85px!important;margin-bottom:85px!important} +.mrg-vertical-90{margin-top:90px!important;margin-bottom:90px!important} +.mrg-vertical-95{margin-top:95px!important;margin-bottom:95px!important} +.mrg-vertical-100{margin-top:100px!important;margin-bottom:100px!important} +.mrg-vertical-105{margin-top:105px!important;margin-bottom:105px!important} +.mrg-vertical-110{margin-top:110px!important;margin-bottom:110px!important} +.mrg-vertical-115{margin-top:115px!important;margin-bottom:115px!important} +.mrg-vertical-120{margin-top:120px!important;margin-bottom:120px!important} +.mrg-vertical-125{margin-top:125px!important;margin-bottom:125px!important} +.mrg-vertical-130{margin-top:130px!important;margin-bottom:130px!important} +.mrg-vertical-135{margin-top:135px!important;margin-bottom:135px!important} +.mrg-vertical-140{margin-top:140px!important;margin-bottom:140px!important} +.mrg-vertical-145{margin-top:145px!important;margin-bottom:145px!important} +.mrg-vertical-150{margin-top:150px!important;margin-bottom:150px!important} + +.mrg-horizon-5{margin-left:5px!important;margin-right:5px!important} +.mrg-horizon-10{margin-left:10px!important;margin-right:10px!important} +.mrg-horizon-15{margin-left:15px!important;margin-right:15px!important} +.mrg-horizon-20{margin-left:20px!important;margin-right:20px!important} +.mrg-horizon-25{margin-left:25px!important;margin-right:25px!important} +.mrg-horizon-30{margin-left:30px!important;margin-right:30px!important} +.mrg-horizon-35{margin-left:35px!important;margin-right:35px!important} +.mrg-horizon-40{margin-left:40px!important;margin-right:40px!important} +.mrg-horizon-45{margin-left:45px!important;margin-right:45px!important} +.mrg-horizon-50{margin-left:50px!important;margin-right:50px!important} +.mrg-horizon-55{margin-left:55px!important;margin-right:55px!important} +.mrg-horizon-60{margin-left:60px!important;margin-right:60px!important} +.mrg-horizon-65{margin-left:65px!important;margin-right:65px!important} +.mrg-horizon-70{margin-left:70px!important;margin-right:70px!important} +.mrg-horizon-75{margin-left:75px!important;margin-right:75px!important} +.mrg-horizon-80{margin-left:80px!important;margin-right:80px!important} +.mrg-horizon-85{margin-left:85px!important;margin-right:85px!important} +.mrg-horizon-90{margin-left:90px!important;margin-right:90px!important} +.mrg-horizon-95{margin-left:95px!important;margin-right:95px!important} +.mrg-horizon-100{margin-left:100px!important;margin-right:100px!important} +.mrg-horizon-105{margin-left:105px!important;margin-right:105px!important} +.mrg-horizon-110{margin-left:110px!important;margin-right:110px!important} +.mrg-horizon-115{margin-left:115px!important;margin-right:115px!important} +.mrg-horizon-120{margin-left:120px!important;margin-right:120px!important} +.mrg-horizon-125{margin-left:125px!important;margin-right:125px!important} +.mrg-horizon-130{margin-left:130px!important;margin-right:130px!important} +.mrg-horizon-135{margin-left:135px!important;margin-right:135px!important} +.mrg-horizon-140{margin-left:140px!important;margin-right:140px!important} +.mrg-horizon-145{margin-left:145px!important;margin-right:145px!important} +.mrg-horizon-150{margin-left:150px!important;margin-right:150px!important} + +.mrg-top-0{margin-top:0px!important} +.mrg-top-5{margin-top:5px!important} +.mrg-top-10{margin-top:10px!important} +.mrg-top-15{margin-top:15px!important} +.mrg-top-20{margin-top:20px!important} +.mrg-top-25{margin-top:25px!important} +.mrg-top-30{margin-top:30px!important} +.mrg-top-35{margin-top:35px!important} +.mrg-top-40{margin-top:40px!important} +.mrg-top-45{margin-top:45px!important} +.mrg-top-50{margin-top:50px!important} +.mrg-top-55{margin-top:55px!important} +.mrg-top-60{margin-top:60px!important} +.mrg-top-65{margin-top:65px!important} +.mrg-top-70{margin-top:70px!important} +.mrg-top-75{margin-top:75px!important} +.mrg-top-80{margin-top:80px!important} +.mrg-top-85{margin-top:85px!important} +.mrg-top-90{margin-top:90px!important} +.mrg-top-95{margin-top:95px!important} +.mrg-top-100{margin-top:100px!important} +.mrg-top-105{margin-top:105px!important} +.mrg-top-110{margin-top:110px!important} +.mrg-top-115{margin-top:115px!important} +.mrg-top-120{margin-top:120px!important} +.mrg-top-125{margin-top:125px!important} +.mrg-top-130{margin-top:130px!important} +.mrg-top-135{margin-top:135px!important} +.mrg-top-140{margin-top:140px!important} +.mrg-top-145{margin-top:145px!important} +.mrg-top-150{margin-top:150px!important} + +.mrg-right-0{margin-right:0px!important} +.mrg-right-5{margin-right:5px!important} +.mrg-right-10{margin-right:10px!important} +.mrg-right-15{margin-right:15px!important} +.mrg-right-20{margin-right:20px!important} +.mrg-right-25{margin-right:25px!important} +.mrg-right-30{margin-right:30px!important} +.mrg-right-35{margin-right:35px!important} +.mrg-right-40{margin-right:40px!important} +.mrg-right-45{margin-right:45px!important} +.mrg-right-50{margin-right:50px!important} +.mrg-right-55{margin-right:55px!important} +.mrg-right-60{margin-right:60px!important} +.mrg-right-65{margin-right:65px!important} +.mrg-right-70{margin-right:70px!important} +.mrg-right-75{margin-right:75px!important} +.mrg-right-80{margin-right:80px!important} +.mrg-right-85{margin-right:85px!important} +.mrg-right-90{margin-right:90px!important} +.mrg-right-95{margin-right:95px!important} +.mrg-right-100{margin-right:100px!important} +.mrg-right-105{margin-right:105px!important} +.mrg-right-110{margin-right:110px!important} +.mrg-right-115{margin-right:115px!important} +.mrg-right-120{margin-right:120px!important} +.mrg-right-125{margin-right:125px!important} +.mrg-right-130{margin-right:130px!important} +.mrg-right-135{margin-right:135px!important} +.mrg-right-140{margin-right:140px!important} +.mrg-right-145{margin-right:145px!important} +.mrg-right-150{margin-right:150px!important} + +.mrg-btm-0{margin-bottom:0px!important} +.mrg-btm-5{margin-bottom:5px!important} +.mrg-btm-10{margin-bottom:10px!important} +.mrg-btm-15{margin-bottom:15px!important} +.mrg-btm-20{margin-bottom:20px!important} +.mrg-btm-25{margin-bottom:25px!important} +.mrg-btm-30{margin-bottom:30px!important} +.mrg-btm-35{margin-bottom:35px!important} +.mrg-btm-40{margin-bottom:40px!important} +.mrg-btm-45{margin-bottom:45px!important} +.mrg-btm-50{margin-bottom:50px!important} +.mrg-btm-55{margin-bottom:55px!important} +.mrg-btm-60{margin-bottom:60px!important} +.mrg-btm-65{margin-bottom:65px!important} +.mrg-btm-70{margin-bottom:70px!important} +.mrg-btm-75{margin-bottom:75px!important} +.mrg-btm-80{margin-bottom:80px!important} +.mrg-btm-85{margin-bottom:85px!important} +.mrg-btm-90{margin-bottom:90px!important} +.mrg-btm-95{margin-bottom:95px!important} +.mrg-btm-100{margin-bottom:100px!important} +.mrg-btm-105{margin-bottom:105px!important} +.mrg-btm-110{margin-bottom:110px!important} +.mrg-btm-115{margin-bottom:115px!important} +.mrg-btm-120{margin-bottom:120px!important} +.mrg-btm-125{margin-bottom:125px!important} +.mrg-btm-130{margin-bottom:130px!important} +.mrg-btm-135{margin-bottom:135px!important} +.mrg-btm-140{margin-bottom:140px!important} +.mrg-btm-145{margin-bottom:145px!important} +.mrg-btm-150{margin-bottom:150px!important} + +.mrg-left-0{margin-left:0px!important} +.mrg-left-5{margin-left:5px!important} +.mrg-left-10{margin-left:10px!important} +.mrg-left-15{margin-left:15px!important} +.mrg-left-20{margin-left:20px!important} +.mrg-left-25{margin-left:25px!important} +.mrg-left-30{margin-left:30px!important} +.mrg-left-35{margin-left:35px!important} +.mrg-left-40{margin-left:40px!important} +.mrg-left-45{margin-left:45px!important} +.mrg-left-50{margin-left:50px!important} +.mrg-left-55{margin-left:55px!important} +.mrg-left-60{margin-left:60px!important} +.mrg-left-65{margin-left:65px!important} +.mrg-left-70{margin-left:70px!important} +.mrg-left-75{margin-left:75px!important} +.mrg-left-80{margin-left:80px!important} +.mrg-left-85{margin-left:85px!important} +.mrg-left-90{margin-left:90px!important} +.mrg-left-95{margin-left:95px!important} +.mrg-left-100{margin-left:100px!important} +.mrg-left-105{margin-left:105px!important} +.mrg-left-110{margin-left:110px!important} +.mrg-left-115{margin-left:115px!important} +.mrg-left-120{margin-left:120px!important} +.mrg-left-125{margin-left:125px!important} +.mrg-left-130{margin-left:130px!important} +.mrg-left-135{margin-left:135px!important} +.mrg-left-140{margin-left:140px!important} +.mrg-left-145{margin-left:145px!important} +.mrg-left-150{margin-left:150px!important} + +.no-pdd{padding:0!important} +.no-pdd-top{padding-top:0!important} +.no-pdd-btm{padding-bottom:0!important} +.no-pdd-left{padding-left:0!important} +.no-pdd-right{padding-right:0!important} +.no-pdd-vertical{padding-top:0!important;padding-bottom:0!important} +.no-pdd-horizon{padding-left:0!important;padding-right:0!important} + +.padding-5{padding:5px!important} +.padding-10{padding:10px!important} +.padding-15{padding:15px!important} +.padding-20{padding:20px!important} +.padding-25{padding:25px!important} +.padding-30{padding:30px!important} +.padding-35{padding:35px!important} +.padding-40{padding:40px!important} +.padding-45{padding:45px!important} +.padding-50{padding:50px!important} +.padding-55{padding:55px!important} +.padding-60{padding:60px!important} +.padding-65{padding:65px!important} +.padding-70{padding:70px!important} +.padding-75{padding:75px!important} +.padding-80{padding:80px!important} +.padding-85{padding:85px!important} +.padding-90{padding:90px!important} +.padding-95{padding:95px!important} +.padding-100{padding:100px!important} +.padding-105{padding:105px!important} +.padding-110{padding:110px!important} +.padding-115{padding:115px!important} +.padding-120{padding:120px!important} +.padding-125{padding:125px!important} +.padding-130{padding:130px!important} +.padding-135{padding:135px!important} +.padding-140{padding:140px!important} +.padding-145{padding:145px!important} +.padding-150{padding:150px!important} + +.pdd-vertical-5{padding-top:5px!important;padding-bottom:5px!important} +.pdd-vertical-10{padding-top:10px!important;padding-bottom:10px!important} +.pdd-vertical-15{padding-top:15px!important;padding-bottom:15px!important} +.pdd-vertical-20{padding-top:20px!important;padding-bottom:20px!important} +.pdd-vertical-25{padding-top:25px!important;padding-bottom:25px!important} +.pdd-vertical-30{padding-top:30px!important;padding-bottom:30px!important} +.pdd-vertical-35{padding-top:35px!important;padding-bottom:35px!important} +.pdd-vertical-40{padding-top:40px!important;padding-bottom:40px!important} +.pdd-vertical-45{padding-top:45px!important;padding-bottom:45px!important} +.pdd-vertical-50{padding-top:50px!important;padding-bottom:50px!important} +.pdd-vertical-55{padding-top:55px!important;padding-bottom:55px!important} +.pdd-vertical-60{padding-top:60px!important;padding-bottom:60px!important} +.pdd-vertical-65{padding-top:65px!important;padding-bottom:65px!important} +.pdd-vertical-70{padding-top:70px!important;padding-bottom:70px!important} +.pdd-vertical-75{padding-top:75px!important;padding-bottom:75px!important} +.pdd-vertical-80{padding-top:80px!important;padding-bottom:80px!important} +.pdd-vertical-85{padding-top:85px!important;padding-bottom:85px!important} +.pdd-vertical-90{padding-top:90px!important;padding-bottom:90px!important} +.pdd-vertical-95{padding-top:95px!important;padding-bottom:95px!important} +.pdd-vertical-100{padding-top:100px!important;padding-bottom:100px!important} +.pdd-vertical-105{padding-top:105px!important;padding-bottom:105px!important} +.pdd-vertical-110{padding-top:110px!important;padding-bottom:110px!important} +.pdd-vertical-115{padding-top:115px!important;padding-bottom:115px!important} +.pdd-vertical-120{padding-top:120px!important;padding-bottom:120px!important} +.pdd-vertical-125{padding-top:125px!important;padding-bottom:125px!important} +.pdd-vertical-130{padding-top:130px!important;padding-bottom:130px!important} +.pdd-vertical-135{padding-top:135px!important;padding-bottom:135px!important} +.pdd-vertical-140{padding-top:140px!important;padding-bottom:140px!important} +.pdd-vertical-145{padding-top:145px!important;padding-bottom:145px!important} +.pdd-vertical-150{padding-top:150px!important;padding-bottom:150px!important} + +.pdd-horizon-5{padding-left:5px!important;padding-right:5px!important} +.pdd-horizon-10{padding-left:10px!important;padding-right:10px!important} +.pdd-horizon-15{padding-left:15px!important;padding-right:15px!important} +.pdd-horizon-20{padding-left:20px!important;padding-right:20px!important} +.pdd-horizon-25{padding-left:25px!important;padding-right:25px!important} +.pdd-horizon-30{padding-left:30px!important;padding-right:30px!important} +.pdd-horizon-35{padding-left:35px!important;padding-right:35px!important} +.pdd-horizon-40{padding-left:40px!important;padding-right:40px!important} +.pdd-horizon-45{padding-left:45px!important;padding-right:45px!important} +.pdd-horizon-50{padding-left:50px!important;padding-right:50px!important} +.pdd-horizon-55{padding-left:55px!important;padding-right:55px!important} +.pdd-horizon-60{padding-left:60px!important;padding-right:60px!important} +.pdd-horizon-65{padding-left:65px!important;padding-right:65px!important} +.pdd-horizon-70{padding-left:70px!important;padding-right:70px!important} +.pdd-horizon-75{padding-left:75px!important;padding-right:75px!important} +.pdd-horizon-80{padding-left:80px!important;padding-right:80px!important} +.pdd-horizon-85{padding-left:85px!important;padding-right:85px!important} +.pdd-horizon-90{padding-left:90px!important;padding-right:90px!important} +.pdd-horizon-95{padding-left:95px!important;padding-right:95px!important} +.pdd-horizon-100{padding-left:100px!important;padding-right:100px!important} +.pdd-horizon-105{padding-left:105px!important;padding-right:105px!important} +.pdd-horizon-110{padding-left:110px!important;padding-right:110px!important} +.pdd-horizon-115{padding-left:115px!important;padding-right:115px!important} +.pdd-horizon-120{padding-left:120px!important;padding-right:120px!important} +.pdd-horizon-125{padding-left:125px!important;padding-right:125px!important} +.pdd-horizon-130{padding-left:130px!important;padding-right:130px!important} +.pdd-horizon-135{padding-left:135px!important;padding-right:135px!important} +.pdd-horizon-140{padding-left:140px!important;padding-right:140px!important} +.pdd-horizon-145{padding-left:145px!important;padding-right:145px!important} +.pdd-horizon-150{padding-left:150px!important;padding-right:150px!important} + +.pdd-top-0{padding-top:0px!important} +.pdd-top-5{padding-top:5px!important} +.pdd-top-10{padding-top:10px!important} +.pdd-top-15{padding-top:15px!important} +.pdd-top-20{padding-top:20px!important} +.pdd-top-25{padding-top:25px!important} +.pdd-top-30{padding-top:30px!important} +.pdd-top-35{padding-top:35px!important} +.pdd-top-40{padding-top:40px!important} +.pdd-top-45{padding-top:45px!important} +.pdd-top-50{padding-top:50px!important} +.pdd-top-55{padding-top:55px!important} +.pdd-top-60{padding-top:60px!important} +.pdd-top-65{padding-top:65px!important} +.pdd-top-70{padding-top:70px!important} +.pdd-top-75{padding-top:75px!important} +.pdd-top-80{padding-top:80px!important} +.pdd-top-85{padding-top:85px!important} +.pdd-top-90{padding-top:90px!important} +.pdd-top-95{padding-top:95px!important} +.pdd-top-100{padding-top:100px!important} +.pdd-top-105{padding-top:105px!important} +.pdd-top-110{padding-top:110px!important} +.pdd-top-115{padding-top:115px!important} +.pdd-top-120{padding-top:120px!important} +.pdd-top-125{padding-top:125px!important} +.pdd-top-130{padding-top:130px!important} +.pdd-top-135{padding-top:135px!important} +.pdd-top-140{padding-top:140px!important} +.pdd-top-145{padding-top:145px!important} +.pdd-top-150{padding-top:150px!important} + +.pdd-right-0{padding-right:0px!important} +.pdd-right-5{padding-right:5px!important} +.pdd-right-10{padding-right:10px!important} +.pdd-right-15{padding-right:15px!important} +.pdd-right-20{padding-right:20px!important} +.pdd-right-25{padding-right:25px!important} +.pdd-right-30{padding-right:30px!important} +.pdd-right-35{padding-right:35px!important} +.pdd-right-40{padding-right:40px!important} +.pdd-right-45{padding-right:45px!important} +.pdd-right-50{padding-right:50px!important} +.pdd-right-55{margin-right:55px!important} +.pdd-right-60{padding-right:60px!important} +.pdd-right-65{padding-right:65px!important} +.pdd-right-70{padding-right:70px!important} +.pdd-right-75{padding-right:75px!important} +.pdd-right-80{padding-right:80px!important} +.pdd-right-85{padding-right:85px!important} +.pdd-right-90{padding-right:90px!important} +.pdd-right-95{padding-right:95px!important} +.pdd-right-100{padding-right:100px!important} +.pdd-right-105{padding-right:105px!important} +.pdd-right-110{padding-right:110px!important} +.pdd-right-115{padding-right:115px!important} +.pdd-right-120{margin-right:120px!important} +.pdd-right-125{padding-right:125px!important} +.pdd-right-130{padding-right:130px!important} +.pdd-right-135{padding-right:135px!important} +.pdd-right-140{padding-right:140px!important} +.pdd-right-145{padding-right:145px!important} +.pdd-right-150{padding-right:150px!important} + +.pdd-left-0{padding-left:0px!important} +.pdd-left-5{padding-left:5px!important} +.pdd-left-10{padding-left:10px!important} +.pdd-left-15{padding-left:15px!important} +.pdd-left-20{padding-left:20px!important} +.pdd-left-25{padding-left:25px!important} +.pdd-left-30{padding-left:30px!important} +.pdd-left-35{padding-left:35px!important} +.pdd-left-40{padding-left:40px!important} +.pdd-left-45{padding-left:45px!important} +.pdd-left-50{padding-left:50px!important} +.pdd-left-55{margin-left:55px!important} +.pdd-left-60{padding-left:60px!important} +.pdd-left-65{padding-left:65px!important} +.pdd-left-70{padding-left:70px!important} +.pdd-left-75{padding-left:75px!important} +.pdd-left-80{padding-left:80px!important} +.pdd-left-85{padding-left:85px!important} +.pdd-left-90{padding-left:90px!important} +.pdd-left-95{padding-left:95px!important} +.pdd-left-100{padding-left:100px!important} +.pdd-left-105{padding-left:105px!important} +.pdd-left-110{padding-left:110px!important} +.pdd-left-115{padding-left:115px!important} +.pdd-left-120{margin-left:120px!important} +.pdd-left-125{padding-left:125px!important} +.pdd-left-130{padding-left:130px!important} +.pdd-left-135{padding-left:135px!important} +.pdd-left-140{padding-left:140px!important} +.pdd-left-145{padding-left:145px!important} +.pdd-left-150{padding-left:150px!important} + +.pdd-btm-0{padding-bottom:0px!important} +.pdd-btm-5{padding-bottom:5px!important} +.pdd-btm-10{padding-bottom:10px!important} +.pdd-btm-15{padding-bottom:15px!important} +.pdd-btm-20{padding-bottom:20px!important} +.pdd-btm-25{padding-bottom:25px!important} +.pdd-btm-30{padding-bottom:30px!important} +.pdd-btm-35{padding-bottom:35px!important} +.pdd-btm-40{padding-bottom:40px!important} +.pdd-btm-45{padding-bottom:45px!important} +.pdd-btm-50{padding-bottom:50px!important} +.pdd-btm-55{margin-bottom:55px!important} +.pdd-btm-60{padding-bottom:60px!important} +.pdd-btm-65{padding-bottom:65px!important} +.pdd-btm-70{padding-bottom:70px!important} +.pdd-btm-75{padding-bottom:75px!important} +.pdd-btm-80{padding-bottom:80px!important} +.pdd-btm-85{padding-bottom:85px!important} +.pdd-btm-90{padding-bottom:90px!important} +.pdd-btm-95{padding-bottom:95px!important} +.pdd-btm-100{padding-bottom:100px!important} +.pdd-btm-105{padding-bottom:105px!important} +.pdd-btm-110{padding-bottom:110px!important} +.pdd-btm-115{padding-bottom:115px!important} +.pdd-btm-120{margin-bottom:120px!important} +.pdd-btm-125{padding-bottom:125px!important} +.pdd-btm-130{padding-bottom:130px!important} +.pdd-btm-135{padding-bottom:135px!important} +.pdd-btm-140{padding-bottom:140px!important} +.pdd-btm-145{padding-bottom:145px!important} +.pdd-btm-150{padding-bottom:150px!important} + +.no-border{border:0!important;border-radius:0!important} + +.vertical-align{display:table;height:100%;width:100%} +.vertical-align +.table-cell{display:table-cell;vertical-align:middle +}.vertical-align-super{vertical-align:super} +.border-radius-4{border-radius:4px!important} +.border-radius-6{border-radius:6px!important} +.border-radius-8{border-radius:8px!important} +.border-radius-10{border-radius:10px!important} +.border-radius-round{border-radius:50px!important} + +.header .header-container:after,.header .header-container:before{content:" ";display:table} +.header .header-container:after{clear:both} +.header .header-container .nav-left,.header .header-container .nav-right{position:relative;list-style:none;padding-left:0;margin-bottom:0} +.header .header-container .nav-left>li,.header .header-container .nav-right>li{float:left} +.header .header-container .nav-left>li>a,.header .header-container .nav-right>li>a{padding:0 15px;line-height:56px;min-height:56px;color:#333;display:block;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out} +.header .header-container .nav-left>li>a i,.header .header-container .nav-right>li>a i{font-size:18px} +.header .header-container .nav-left>li>a:focus,.header .header-container .nav-left>li>a:hover,.header .header-container .nav-right>li>a:focus,.header .header-container .nav-right>li>a:hover{text-decoration:none;color:#333} +@media only screen and (max-width:992px){.header .header-container .nav-left>li>a,.header .header-container .nav-right>li>a{padding:0 15px}} +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile,.header .header-container .nav-right .user-profile{border-right:0;border-left:0} +} +.header .header-container .nav-left .user-profile .profile-img,.header .header-container .nav-right .user-profile .profile-img{display:inline-block;width:35px; height: 35px; heborder-radius:50%;float:left} +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile .profile-img,.header .header-container .nav-right .user-profile .profile-img{width:30px;margin-right:0} +} +.header .header-container .nav-left .user-profile .user-info,.header .header-container .nav-right .user-profile .user-info{display:inline-block} +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile .user-info,.header .header-container .nav-right .user-profile .user-info{display:none} +} +.header .header-container .nav-left .user-profile .dropdown-menu>li>a,.header .header-container .nav-right .user-profile .dropdown-menu>li>a{color:#333} +.header .header-container .nav-left .notifications,.header .header-container .nav-right .notifications{position:relative} +.header .header-container .nav-left .notifications .counter,.header .header-container .nav-right .notifications .counter{position:absolute;right:6px;top:12px;background-color:#ff3c7e;color:#fff;padding:3px 5.5px;border-radius:50px;line-height:1;font-size:10px} +.header .header-container .nav-left .notifications .dropdown-menu,.header .header-container .nav-right .notifications .dropdown-menu{min-width:350px;padding:0} +@media only screen and (max-width:767px){ + .header .header-container .nav-left .notifications .dropdown-menu,.header .header-container .nav-right .notifications .dropdown-menu{max-width:300px} +} +.header .header-container .nav-left .notifications .dropdown-menu .list-info,.header .header-container .nav-right .notifications .dropdown-menu .list-info{max-height:248px;overflow-y:auto;position:relative} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a{padding:20px 15px;font-size:13px;display:block;border-bottom:1px solid #e6ecf5;transition:all .15s ease-out;-webkit-transition:all .15s ease-out;-moz-transition:all .15s ease-out;-o-transition:all .15s ease-out;-ms-transition:all .15s ease-out} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a:focus,.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a:hover,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a:focus,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a:hover{color:#333;text-decoration:none;background-color:#f6f7fb} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a .sub-title,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a .sub-title{padding-top:3px} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li:last-child a,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li:last-child a{border-bottom:0} +.header .header-container .nav-left .notifications .dropdown-menu .notice-header,.header .header-container .nav-right .notifications .dropdown-menu .notice-header{padding:15px 20px;border-bottom:1px solid #e6ecf5} +.header .header-container .nav-left .notifications .dropdown-menu .notice-footer,.header .header-container .nav-right .notifications .dropdown-menu .notice-footer{text-align:center;padding:15px 20px;border-top:1px solid #e6ecf5} +.header .header-container .nav-left .notifications .dropdown-menu .notice-footer a,.header .header-container .nav-right .notifications .dropdown-menu .notice-footer a{display:block} +.header .header-container .nav-left .notifications .dropdown-menu.list-info,.header .header-container .nav-right .notifications .dropdown-menu.list-info{position:absolute} +.header .header-container .dropdown-menu{transform-origin:top right;transform:scale(0);-webkit-transform:scale(0);-moz-transform:scale(0);-o-transform:scale(0);-ms-transform:scale(0);transition:transform .15s ease-out;-webkit-transition:transform .15s ease-out;-moz-transition:transform .15s ease-out;-o-transition:transform .15s ease-out;-ms-transition:transform .15s ease-out;display:block;margin:0} +.header .header-container .dropdown-menu .divider{border-bottom:1px solid #e6ecf5;height:1px;overflow:hidden}.header .header-container .dropdown-menu>li>a{transition:all .2s ease-out;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;-ms-transition:all .2s ease-out} +.header .header-container .show .dropdown-menu{transform:scale(1);-webkit-transform:scale(1);-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1)} +.header .header-container .nav-left{float:left;margin-left:15px}.header .header-container .nav-right{float:right} +.header .header-container .nav-right .dropdown-menu{left:auto;right:0}.header .header-container .nav-right .dropdown-menu>li{width:100%} +.header .header-container .nav-right .dropdown-menu>li>a{line-height:1.5;min-height:auto;padding:10px 15px} +.header .search-box.active .search-icon,.header .search-box .search-icon-close{display:none} +.header .search-box.active .search-icon-close{display:inline-block} +.header .search-input{display:none} +.header .search-input.active{display:inline-block} +.header .search-input input{border:0;box-shadow:none;background-color:transparent;outline:none;height:40px;margin-top:12px;padding:5px;font-size:18px} +@media only screen and (max-width:767px){.header .search-input input{width:85px}} +.header .search-input input::-webkit-input-placeholder{font-style:italic;color:#c3c5d3} +.header .search-input input:-moz-placeholder,.header .search-input input::-moz-placeholder{font-style:italic;color:#c3c5d3} +.header .search-input input:-ms-input-placeholder{font-style:italic;color:#c3c5d3} +.header .search-input .advanced-search{display:none;position:absolute;top:59px;width:380px;min-height:50px;max-height:500px;background-color:#fff;border-radius:4px;box-shadow:0 0 8px 0 rgba(0,0,0,.2)} +@media only screen and (max-width:767px){.header .search-input .advanced-search{left:40px}} +.header .search-input .advanced-search.active{display:block} +.header .search-input .advanced-search .search-wrapper{position:relative} +.header .search-input .advanced-search .search-wrapper ul>li>a{padding:12px 20px} +.header .search-input .advanced-search .search-wrapper ul>li>a:focus,.header .search-input .advanced-search .search-wrapper ul>li>a:hover{background-color:#f6f7fb} +.header .search-input .search-footer{border-top:1px solid #e6ecf5;text-align:center;padding:15px;border-bottom-left-radius:4px;border-bottom-right-radius:4px} + +.is-collapsed .header{width:calc(100% - 70px)} +@media only screen and (max-width:992px){.is-collapsed .header{width:100%}} + +@media only screen and (min-width:992px) and (max-width:1440px){ + .is-collapsed .header{width:calc(100% - 260px)} +} +.content-footer{padding:0 30px} +.content-footer .footer{padding:20px 0;font-size:90%;border-top:1px solid #e6ecf5} +.content-footer .footer .go-right{float:right} +.widget-news-1 .news-wrapper{background-repeat:no-repeat;background-size:cover;background-position:50%;min-height:400px;padding:15px +}.widget-news-1 .news-wrapper.wrapper-pdd-lg{padding:40px 120px} +.widget-news-1 .news-wrapper.wrapper-pdd-md{padding:30px 50px} +.widget-news-1 .news-wrapper.wrapper-pdd-sm{padding:30px} +.widget-news-1 .news-wrapper .user-thumbnail .user-img{display:inline-block;width:60px;border-radius:50%;float:left} +.widget-news-1 .news-wrapper .user-thumbnail .user-info{display:inline-block;margin-left:10px;color:#fff;padding-top:5px} +.widget-news-1 .news-wrapper .user-thumbnail .user-info .name{display:block;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;font-size:16px} +.widget-news-1 .news-wrapper .user-thumbnail .user-info .date{display:block;opacity:.8} +.widget-news-1 .news-wrapper .news-content{position:relative} +.widget-news-1 .news-wrapper .news-content .news-title{color:#fff;font-size:20px;margin-bottom:20px} +.widget-news-1 .news-wrapper .news-content .news-article{color:#ccc} +.widget-profile-1 .profile{text-align:center;padding:10px 20px} +.widget-profile-1 .profile img{border-radius:50%} +.widget-compose{padding:15px} +.widget-compose .composor-tools{padding-left:0;list-style:none} +.widget-compose .composor-tools>li{display:inline-block} +.widget-compose .composor-tools>li>a{display:block;font-weight:700;color:#333;padding:10px} +.widget-compose .composor-tools>li.active a,.widget-compose .composor-tools>li>a:focus,.widget-compose .composor-tools>li>a:hover{color:#333} +.widget-compose textarea.form-control{border:0;min-height:60px;padding:20px 10px} +.widget-feed{padding:25px 30px} +.widget-feed .feed-header{padding-bottom:10px} +.widget-feed .feed-body{padding:15px 0} +.widget-feed .feed-action{padding-left:0;list-style:none} +.widget-feed .feed-action>li{display:inline-block} +.widget-feed .feed-action>li>a{display:block;color:#333;font-size:16px;font-weight:500;padding:10px 25px 10px 0} +.widget-feed .feed-action>li.active a,.widget-feed .feed-action>li>a:focus,.widget-feed .feed-action>li>a:hover{color:#333} +.widget-feed .comment .comment-item{padding:30px 0;border-bottom:1px solid #e6ecf5} +.widget-feed .comment .add-comment textarea{min-height:50px;resize:none;border:0;padding:20px 10px 5px} +.widget-feed .comment .list-info .info{height:auto} +.widget-feed .comment .list-info .info p{margin-bottom:0} +.widget-feed .shared-item{position:relative;border:1px solid #e6ecf5;display:-ms-flexbox;display:flex} +@media only screen and (max-width:767px){.widget-feed .shared-item{max-height:130px;overflow:hidden}} +.widget-feed .shared-item .item-image{-ms-flex:4;flex:4;width:30%} +.widget-feed .shared-item .item-content{-ms-flex:6;flex:6;width:70%;padding:30px} +.widget-feed iframe{border:0;width:100%;min-height:300px} +.widget-weather .today-cel{font-size:60px;font-weight:300;letter-spacing:1.5px;line-height:1} +.widget-weather .today-weather{font-size:60px} +.widget-weather .next-7day{text-align:center} +.widget-project{position:relative;border:1px solid #e6ecf5;background-color:#fff;margin-bottom:30px;padding:20px} +.widget-legends{max-width:150px;margin-left:auto;margin-right:auto} + +button{box-shadow:none;cursor:pointer} +button,button:focus{outline:none} +button.active:focus,button:active:focus{outline:none;box-shadow:none} +button.disabled,button:disabled{opacity:.5;cursor:not-allowed} +.btn{cursor:pointer;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;letter-spacing:1px;font-size:13px;padding:10px 20px;border-radius:6px;margin-right:5px;margin-bottom:10px;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out} +.btn.dropdown-toggle{margin-bottom:0} +.btn:focus{box-shadow:none} +.btn.active:focus,.btn:active:focus,.btn:focus{outline:none} +.btn-inverse{font-weight:700} +.btn-default{color:#333;background-color:#fff;border-color:#d4deee;font-weight:500} +.btn-default.active:focus,.btn-default.active:hover,.btn-default:active,.btn-default:active:focus,.btn-default:active:hover,.btn-default:focus,.btn-default:hover{color:#333;background-color:#edf2f8;border-color:#edf2f8} +.btn-primary{background-color:#7774e7;border-color:#7774e7;color:#fff} +.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#8c8aeb;border-color:#8c8aeb} +.btn-primary.active,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active{background-color:#625ee3;border-color:#625ee3} +.btn-primary.btn-inverse{background-color:#f7f6fe;color:#7774e7;border-color:transparent;box-shadow:none} +.btn-primary.btn-inverse:focus,.btn-primary.btn-inverse:hover{background-color:#e1e1fa;color:#625ee3;border-color:transparent} +.btn-primary.disabled{opacity:.35}.btn-primary.disabled,.btn-primary.disabled:focus,.btn-primary.disabled:hover{background-color:#7774e7;border-color:#7774e7} +.btn-success{background-color:#37c936;border-color:#37c936;color:#fff} +.btn-success:focus,.btn-success:hover{color:#fff;background-color:#4bce4a;border-color:#4bce4a} +.btn-success.active,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active{background-color:#32b531;border-color:#32b531} +.btn-success.btn-inverse{background-color:#ebfaeb;color:#37c936;border-color:transparent;box-shadow:none} +.btn-success.btn-inverse:focus,.btn-success.btn-inverse:hover{background-color:#d7f4d7;color:#32b531;border-color:transparent} +.btn-success.disabled{opacity:.35}.btn-success.disabled,.btn-success.disabled:focus,.btn-success.disabled:hover{background-color:#37c936;border-color:#37c936} +.btn-info{background-color:#0f9aee;border-color:#0f9aee;color:#fff} +.btn-info:focus,.btn-info:hover{color:#fff;background-color:#25a4f1;border-color:#25a4f1} +.btn-info.active,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active{background-color:#0d8ad6;border-color:#0d8ad6} +.btn-info.btn-inverse{background-color:#e5f4fd;color:#0f9aee;border-color:transparent;box-shadow:none} +.btn-info.btn-inverse:focus,.btn-info.btn-inverse:hover{background-color:#cdeafc;color:#0d8ad6;border-color:transparent} +.btn-info.disabled{opacity:.35}.btn-info.disabled,.btn-info.disabled:focus,.btn-info.disabled:hover{background-color:#0f9aee;border-color:#0f9aee} +.btn-warning{color:#fff;background-color:#fc0;border-color:#fc0} +.btn-warning:focus,.btn-warning:hover{color:#fff;background-color:#ffd11a;border-color:#ffd11a} +.btn-warning.active,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active{background-color:#e6b800;border-color:#e6b800} +.btn-warning.btn-inverse{background-color:#fffae6;color:#fc0;border-color:transparent;box-shadow:none} +.btn-warning.btn-inverse:focus,.btn-warning.btn-inverse:hover{background-color:#fff5cc;color:#e6b800;border-color:transparent} +.btn-warning.disabled{opacity:.35}.btn-warning.disabled,.btn-warning.disabled:focus,.btn-warning.disabled:hover{background-color:#fc0;border-color:#fc0} +.btn-danger{color:#fff;background-color:#ff3c7e;border-color:#ff3c7e} +.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#ff568f;border-color:#ff568f} +.btn-danger.active,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active{background-color:#ff236d;border-color:#ff236d} +.btn-danger.btn-inverse{background-color:#ffeff4;color:#ff3c7e;border-color:transparent;box-shadow:none} +.btn-danger.btn-inverse:focus,.btn-danger.btn-inverse:hover{background-color:#ffd5e3;color:#ff236d;border-color:transparent} +.btn-danger.disabled{opacity:.35}.btn-danger.disabled,.btn-danger.disabled:focus,.btn-danger.disabled:hover{background-color:#ff3c7e;border-color:#ff3c7e} +.show>.dropdown-toggle.btn-primary,.show>.dropdown-toggle.btn-primary:focus,.show>.dropdown-toggle.btn-primary:hover{background-color:#625ee3;border-color:#625ee3} +.show>.dropdown-toggle.btn-primary.btn-inverse,.show>.dropdown-toggle.btn-primary.btn-inverse:focus,.show>.dropdown-toggle.btn-primary.btn-inverse:hover{background-color:#e1e1fa;color:#625ee3} +.show>.dropdown-toggle.btn-success,.show>.dropdown-toggle.btn-success:focus,.show>.dropdown-toggle.btn-success:hover{background-color:#32b531;border-color:#32b531} +.show>.dropdown-toggle.btn-success.btn-inverse,.show>.dropdown-toggle.btn-success.btn-inverse:focus,.show>.dropdown-toggle.btn-success.btn-inverse:hover{background-color:#d7f4d7;color:#32b531} +.show>.dropdown-toggle.btn-info,.show>.dropdown-toggle.btn-info:focus,.show>.dropdown-toggle.btn-info:hover{background-color:#0d8ad6;border-color:#0d8ad6} +.show>.dropdown-toggle.btn-info.btn-inverse,.show>.dropdown-toggle.btn-info.btn-inverse:focus,.show>.dropdown-toggle.btn-info.btn-inverse:hover{background-color:#cdeafc;color:#0d8ad6} +.show>.dropdown-toggle.btn-warning,.show>.dropdown-toggle.btn-warning:focus,.show>.dropdown-toggle.btn-warning:hover{background-color:#e6b800;border-color:#e6b800} +.show>.dropdown-toggle.btn-warning.btn-inverse,.show>.dropdown-toggle.btn-warning.btn-inverse:focus,.show>.dropdown-toggle.btn-warning.btn-inverse:hover{background-color:#fff5cc;color:#e6b800} +.show>.dropdown-toggle.btn-danger,.show>.dropdown-toggle.btn-danger:focus,.show>.dropdown-toggle.btn-danger:hover{background-color:#ff236d;border-color:#ff236d} +.show>.dropdown-toggle.btn-danger.btn-inverse,.show>.dropdown-toggle.btn-danger.btn-inverse:focus,.show>.dropdown-toggle.btn-danger.btn-inverse:hover{background-color:#ffd5e3;color:#ff236d} +.btn-flat{border:0;color:#8f92a1;background-color:transparent} +.btn-flat:focus,.btn-flat:hover{background:#e6ecf5;background:rgba(230,236,245,.55);color:#6b7192} +.btn-icon{padding:10px 11px}.btn-facebook{background-color:#3b579d;color:#fff} +.btn-facebook:focus,.btn-facebook:hover{background-color:#5674bf;border-color:#5674bf;color:#fff} +.btn-twitter{background-color:#2caae1;color:#fff} +.btn-twitter:focus,.btn-twitter:hover{background-color:#62c0e9;border-color:#62c0e9;color:#fff} +.btn-instagram{background-color:#5d4a3b;color:#fff} +.btn-instagram:focus,.btn-instagram:hover{background-color:#826853;border-color:#826853;color:#fff} +.btn-google-plus{background-color:#dc4a38;color:#fff} +.btn-google-plus:focus,.btn-google-plus:hover{background-color:#e5796c;border-color:#e5796c;color:#fff} +.btn-dropbox{background-color:#007ee6;color:#fff} +.btn-dropbox:focus,.btn-dropbox:hover{background-color:#249cff;border-color:#249cff;color:#fff} +.btn-dribbble{background-color:#ea4c89;color:#fff} +.btn-dribbble:focus,.btn-dribbble:hover{background-color:#f083ad;border-color:#f083ad;color:#fff} +.btn-yahoo{background-color:#7b0099;color:#fff} +.btn-yahoo:focus,.btn-yahoo:hover{background-color:#ac00d6;border-color:#ac00d6;color:#fff} +.btn-sound-cloud{background-color:#ff6a22;color:#fff} +.btn-sound-cloud:focus,.btn-sound-cloud:hover{background-color:#ff935f;border-color:#ff935f;color:#fff} +.btn-html5{background-color:#f16528;color:#fff} +.btn-html5:focus,.btn-html5:hover{background-color:#f58e61;border-color:#f58e61;color:#fff} +.btn-wordpress{background-color:#0087be;color:#fff} +.btn-wordpress:focus,.btn-wordpress:hover{background-color:#00b2fb;border-color:#00b2fb;color:#fff} +.btn-tumblr{background-color:#36465d;color:#fff} +.btn-tumblr:focus,.btn-tumblr:hover{background-color:#4c6384;border-color:#4c6384;color:#fff} +.btn-skype{background-color:#00aaf1;color:#fff} +.btn-skype:focus,.btn-skype:hover{background-color:#2fc2ff;border-color:#2fc2ff;color:#fff} +.btn-youtube{background-color:#de2825;color:#fff} +.btn-youtube:focus,.btn-youtube:hover{background-color:#e65c5a;border-color:#e65c5a;color:#fff} +.btn-vimeo{background-color:#1bb6ec;color:#fff} +.btn-vimeo:focus,.btn-vimeo:hover{background-color:#53c8f1;border-color:#53c8f1;color:#fff} +.btn-linkedin{background-color:#0177b5;color:#fff} +.btn-linkedin:focus,.btn-linkedin:hover{background-color:#019ff2;border-color:#019ff2;color:#fff} +.btn-pinterest{background-color:#c9181f;color:#fff} +.btn-pinterest:focus,.btn-pinterest:hover{background-color:#e7373e;border-color:#e7373e;color:#fff} + +.btn-group-lg>.btn,.btn-lg{padding:11px 30px;font-size:13px} +.btn-group-sm>.btn,.btn-sm{padding:7px 12px}.btn-xs{font-size:9px;padding:5px 10px} +.btn-rounded{border-radius:50px} +.btn-block{padding-top:12px;padding-bottom:12px} +.btn-group .btn{padding:10px 14px;margin-right:0} +.btn-group.btn-group-vertical .btn{margin-bottom:0} + +.modal.fade .modal-dialog{transition:all .2s ease-out;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;-ms-transition:all .2s ease-out;transform:translateX(0) translateY(0);-webkit-transform:translateX(0) translateY(0);-moz-transform:translateX(0) translateY(0);-o-transform:translateX(0) translateY(0);-ms-transform:translateX(0) translateY(0)} +.modal.fade.slide-in-right .modal-dialog{transform:translateX(100%);-webkit-transform:translateX(100%);-moz-transform:translateX(100%);-o-transform:translateX(100%);-ms-transform:translateX(100%)}.modal.fade.slide-in-right.show .modal-dialog{transform:translateX(0);-webkit-transform:translateX(0);-moz-transform:translateX(0);-o-transform:translateX(0);-ms-transform:translateX(0)} +.modal.fade.slide-in-left .modal-dialog{transform:translateX(-100%);-webkit-transform:translateX(-100%);-moz-transform:translateX(-100%);-o-transform:translateX(-100%);-ms-transform:translateX(-100%)}.modal.fade.slide-in-left.show .modal-dialog{transform:translateX(0);-webkit-transform:translateX(0);-moz-transform:translateX(0);-o-transform:translateX(0);-ms-transform:translateX(0)} +.modal.fade.modal-fs .modal-dialog,.modal.fade.modal-fs.show .modal-dialog{transform:translateY(0);-webkit-transform:translateY(0);-moz-transform:translateY(0);-o-transform:translateY(0);-ms-transform:translateY(0)}.modal-header{padding:15px 20px;padding-bottom:5px;border-bottom:0} +.modal-header h1,.modal-header h2,.modal-header h3,.modal-header h4,.modal-header h5,.modal-header h6{margin-bottom:0} +.modal-body,.modal-footer{padding:15px 20px} +.modal-footer{border-top:1px solid #e6ecf5;text-align:left} +.modal-footer .btn{margin-bottom:0} +.modal-footer .btn+.btn{margin-left:0} +.modal-content{position:relative;background-color:#fff;border:0;border-radius:5px;outline:0;box-shadow:0 3px 9px rgba(0,0,0,.5)} +.modal-left .modal-dialog,.modal-right .modal-dialog{width:400px;height:100%;margin:0 auto 0 0} +@media only screen and (max-width:767px){ + .modal-left .modal-dialog,.modal-right .modal-dialog{width:260px;} +} + +.modal-left .modal-dialog .modal-content,.modal-right .modal-dialog .modal-content{height:100%;border-radius:0} +.modal-left .modal-dialog .modal-content .side-modal-wrapper,.modal-right .modal-dialog .modal-content .side-modal-wrapper{height:100%;padding-left:15px;padding-right:15px;position:relative} +.modal-left .modal-dialog .modal-content .modal-footer,.modal-right .modal-dialog .modal-content .modal-footer{position:absolute;bottom:0;width:calc(100% - 30px);left:15px} +.modal-right .modal-dialog{margin:0 0 0 auto}.modal-backdrop{z-index:1040;background-color:#333} +@media only screen and (min-width:767px){ + .modal-sm{width:350px} +} +.modal-fs .modal-dialog{width:100%;margin:0 auto;height:100%;max-width:none} +.modal-fs .modal-dialog .modal-content{height:100%;border-radius:0;background:#fff;background:hsla(0,0%,100%,.9)} +.modal-fs .modal-close{position:absolute;top:20px;right:20px;padding:7px 10px;border:1px solid #9ea0b1;border-radius:50px;color:#9ea0b1} +.modal-fs .modal-close:focus,.modal-fs .modal-close:hover{color:#333;text-decoration:none;border:1px solid #333} +button,input,textarea{outline:none} +.form-group{margin-bottom:25px} +.form-control{border-radius:2px;box-shadow:none;height:42px;font-size:14px;color:#333;transition:all .2s ease-in;-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;-o-transition:all .2s ease-in;-ms-transition:all .2s ease-in} +.form-control::-webkit-input-placeholder{color:#544E4C} +.form-control:-moz-placeholder,.form-control::-moz-placeholder{color:#544E4C} +.form-control:-ms-input-placeholder{color:#544E4C} +.form-control:focus{outline:0 none;box-shadow:none;border-color:#3daef3} +.form-control.input-sm{height:30px} +.form-control.input-lg{height:50px} +.form-control.error{border-color:#ff3c7e;background-color:#ffeff4} +.form-control.valid{border-color:#37c936;background-color:#ebfaeb;color:#278d26} +.has-success .form-control,.has-success .form-control:focus{box-shadow:none;border-color:#37c936} +.has-success .checkbox,.has-success .checkbox-inline,.has-success.checkbox label .has-success.checkbox-inline label,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.radio-inline label,.has-success.radio label{color:#37c936} +.has-warning .form-control,.has-warning .form-control:focus{box-shadow:none;border-color:#fc0} +.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning.checkbox label .has-warning.checkbox-inline label,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.radio-inline label,.has-warning.radio label{color:#fc0} +.has-error .form-control,.has-error .form-control:focus{box-shadow:none;border-color:#ff3c7e} +.has-error .checkbox,.has-error .checkbox-inline,.has-error.checkbox label .has-error.checkbox-inline label,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.radio-inline label,.has-error.radio label{color:#ff3c7e} +textarea.form-control{min-height:175px} +.input-icon{position:relative} +.input-icon i{position:absolute;left:10px;top:15px;color:#e0e2e9} +.input-icon .form-control{padding-left:40px} +.input-group-text{background-color:transparent;} +.input-group-text .btn{margin:0;padding:0;background-color:transparent} +.timepicker-input .input-group-text{cursor:pointer} +.checkbox{padding:7px 0;min-height:auto} + +.checkbox input[type=checkbox]{margin:0;display:none;width:22px} +.checkbox input[type=checkbox]+label{padding-left:0} +.checkbox input[type=checkbox]+label:before{content:"";width:22px;height:22px;display:inline-block;border:2px solid #e6ecf5;border-radius:3px;margin-right:10px;font-size:15px;font-family:themify;font-weight:400;line-height:19px;vertical-align:bottom;text-align:center;background-color:#fff;cursor:pointer} +.checkbox input[type=checkbox]:checked+label:before{content:"\E64C";color:#0f9aee} +.checkbox.checkbox-primary input[type=checkbox]:checked+label:before{content:"\E64C";color:#7774e7} +.checkbox.checkbox-success input[type=checkbox]:checked+label:before{content:"\E64C";color:#37c936} +.checkbox.checkbox-warning input[type=checkbox]:checked+label:before{content:"\E64C";color:#fc0} +.checkbox.checkbox-danger input[type=checkbox]:checked+label:before{content:"\E64C";color:#ff3c7e} +.radio{padding:7px 0;min-height:auto}.radio input[type=radio]{margin:0;display:none;width:22px} +.radio input[type=radio]+label{padding-left:0}.radio input[type=radio]+label:before{content:"";width:22px;height:22px;display:inline-block;border:2px solid #e6ecf5;border-radius:50%;margin-right:10px;font-size:14px;font-family:FontAwesome;font-weight:400;line-height:19px;vertical-align:bottom;text-align:center;background-color:#fff;cursor:pointer} +.radio input[type=radio]:checked+label:before{content:"\F111";color:#0f9aee} +.radio.radio-primary input[type=radio]:checked+label:before{content:"\F111";color:#7774e7} +.radio.radio-success input[type=radio]:checked+label:before{content:"\F111";color:#37c936} +.radio.radio-warning input[type=radio]:checked+label:before{content:"\F111";color:#fc0} +.radio.radio-danger input[type=radio]:checked+label:before{content:"\F111";color:#ff3c7e} +.checkbox label,.radio label{cursor:pointer}.checkbox-inline,.radio-inline{margin-right:15px;margin-top:0;display:inline-block} +.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:0} +.toggle-checkbox input[type=checkbox]{opacity:0;position:absolute}.toggle-checkbox input[type=checkbox]+label{position:relative;display:inline-block;transition:.4s ease;-webkit-transition:.4s ease;-moz-transition:.4s ease;-o-transition:.4s ease;-ms-transition:.4s ease;height:30px;width:50px;border:1px solid #e6ecf5;border-radius:60px;cursor:pointer} +.toggle-checkbox input[type=checkbox]+label:before{content:"";position:absolute;display:block;transition:.2s cubic-bezier(.24,0,.5,1);-webkit-transition:.2s cubic-bezier(.24,0,.5,1);-moz-transition:.2s cubic-bezier(.24,0,.5,1);-o-transition:.2s cubic-bezier(.24,0,.5,1);-ms-transition:.2s cubic-bezier(.24,0,.5,1);height:30px;width:50px;top:0;left:0;border-radius:30px} +.toggle-checkbox input[type=checkbox]+label:after{content:"";position:absolute;display:block;box-shadow:0 0 0 1px rgba(0,0,0,.1),0 4px 0 0 rgba(0,0,0,.04),0 4px 9px rgba(0,0,0,.13),0 3px 3px rgba(0,0,0,.05);transition:.35s cubic-bezier(.54,1.6,.5,1);-webkit-transition:.35s cubic-bezier(.54,1.6,.5,1);-moz-transition:.35s cubic-bezier(.54,1.6,.5,1);-o-transition:.35s cubic-bezier(.54,1.6,.5,1);-ms-transition:.35s cubic-bezier(.54,1.6,.5,1);background:#f7f7f7;height:28px;width:28px;top:0;left:0;border-radius:60px} +.toggle-checkbox input[type=checkbox]:checked+label:before{background:#0f9aee;transition:width .2s cubic-bezier(0,0,0,.1);-webkit-transition:width .2s cubic-bezier(0,0,0,.1);-moz-transition:width .2s cubic-bezier(0,0,0,.1);-o-transition:width .2s cubic-bezier(0,0,0,.1);-ms-transition:width .2s cubic-bezier(0,0,0,.1)} +.toggle-checkbox input[type=checkbox]:checked+label:after{left:24px} +.toggle-checkbox.toggle-sm input[type=checkbox]+label,.toggle-checkbox.toggle-sm input[type=checkbox]+label:before{height:20px;width:35px} +.toggle-checkbox.toggle-sm input[type=checkbox]+label:after{height:19px;width:19px} +.toggle-checkbox.toggle-sm input[type=checkbox]:checked+label:after{left:16px} +.toggle-checkbox.toggle-primary input[type=checkbox]:checked+label:before{background:#7774e7} +.toggle-checkbox.toggle-success input[type=checkbox]:checked+label:before{background:#37c936} +.toggle-checkbox.toggle-warning input[type=checkbox]:checked+label:before{background:#fc0} +.toggle-checkbox.toggle-danger input[type=checkbox]:checked+label:before{background:#ff3c7e} + +.list,.list li{position:relative} +.list li{padding-bottom:10px} +.list.tick{list-style:none;padding-left:0} +.list.tick>li{padding-left:30px} +.list.tick>li:before{content:"\E64C";font-family:themify;position:absolute;left:0} +.list.star{list-style:none;padding-left:0}.list.star>li{padding-left:30px} +.list.star>li:before{content:"\E60A";font-family:themify;position:absolute;left:0} +.list.dash{list-style:none;padding-left:0}.list.dash>li{padding-left:30px} +.list.dash>li:before{content:"-";position:absolute;left:10px} +.list.bullet{list-style:none;padding-left:0}.list.bullet>li{padding-left:30px} +.list.bullet>li:before{content:"\E724";font-family:themify;position:absolute;left:0} +.list.arrow{list-style:none;padding-left:0} +.list.arrow>li{padding-left:30px} +.list.arrow>li:before{content:"\E649";font-family:themify;position:absolute;font-size:10px;left:0;top:4px} +.list.decimal{list-style-type:decimal;padding-left:20px} +.list.decimal li{padding-left:10px} +.list.upper-roman{list-style-type:upper-roman;padding-left:20px} +.list.upper-roman li{padding-left:10px} +.list.lower-alpha{list-style-type:lower-alpha;padding-left:20px} +.list.lower-alpha li{padding-left:10px} +.list.bullet-primary>li:before{color:#7774e7} +.list.bullet-info li:before{color:#0f9aee} +.list.bullet-success li:before{color:#37c936} +.list.bullet-warning li:before{color:#fc0} +.list.bullet-danger li:before{color:#ff3c7e} +.list.bullet-white li:before{color:#fff} +.list.bullet-dark li:before{color:#333} +.list-info{margin-bottom:0;position:relative;padding-left:0;list-style:none} +.list-info,.list-info>li{display:block} +.list-info>li>a{display:block;position:relative;padding:12px 0} +.list-info>li>a:focus,.list-info>li>a:hover{text-decoration:none} +.list-info .thumb-img{line-height:40px;width:40px;text-align:center;font-size:17px;border-radius:50px;float:left} +.list-info img.thumb-img{height:40px;width:40px} +.list-info .info{padding-left:55px;height:auto;position:relative} +.list-info .info .title{display:block;color:#333;line-height:1.5} +.list-info .info .title.pdd-top-5{padding-top:7px!important} +.list-info .info .sub-title{display:block;font-size:12px;color:#b4b7c8;max-width:90%} + +.list-info .info .float-object{position:absolute;right:15px;color:#333;top:50%;font-size:12px;transform:translateY(-50%);-webkit-transform:translateY(-50%);-moz-transform:translateY(-50%);-o-transform:translateY(-50%);-ms-transform:translateY(-50%)}.list-members{display:inline-block;margin-bottom:0;overflow:hidden} +.list-members>li{float:left}.list-members>li>a img,.list-members>li>img{width:35px;height:35px;border-radius:100%;overflow:hidden;border:2px solid #fff;display:block} +.list-members>li.all-members{border-radius:100%} +.list-members>li.all-members>a{width:35px;line-height:35px;display:block;text-align:center;border-radius:100%;background-color:#f6f7fb;color:#333} +.list-members>li.add-member>a{border:2px dashed #e6ecf5;width:35px;line-height:30px;display:block;text-align:center;border-radius:100%;color:#c2d0e6;margin-left:5px} +.list-link{margin-bottom:0} +.list-link li{padding:10px 0} +.list-link li a{color:#333} +.list-link li a:focus,.list-link li a:hover{color:#333;text-decoration:none} +.status{width:10px;height:10px;background-color:#fff;border-radius:50px;border:3px solid;border-color:#e6ecf5;position:absolute;top:8px;left:0} +.status.online,.status.success{border-color:#37c936} +.status.danger,.status.no-disturb{border-color:#ff3c7e} +.status.away,.status.warning{border-color:#fc0} +.status.info{border-color:#0f9aee} +.status.primary{border-color:#7774e7} +.label,.tag{padding:4px 10px;border-radius:50px;font-size:75%;font-weight:700;line-height:1} + +.label-lg,.tag-lg{font-size:16px;padding:6px 12px +}label.error{color:#ff3c7e} +label.success{color:#37c936} +.label-primary{background-color:#f7f6fe;color:#7774e7} +.label-success{background-color:#ebfaeb;color:#37c936} +.label-info{background-color:#e5f4fd;color:#0f9aee} +.label-warning{background-color:#fffae6;color:#fc0} +.label-danger{background-color:#ffeff4;color:#ff3c7e} + +.tag{display:inline;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline} +.tag-primary{background-color:#7774e7;color:#fff} +.tag-success{background-color:#37c936;color:#fff} +.tag-info{background-color:#0f9aee;color:#fff} +.tag-warning{background-color:#fc0;color:#fff} +.tag-danger{background-color:#ff3c7e;color:#fff} + +.card{position:relative;background-color:#fff;margin-bottom:30px;border:1px solid #e6ecf5;border-radius:5px;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out} +.card.bg-danger,.card.bg-info,.card.bg-primary,.card.bg-success,.card.bg-warning{color:#e6e6e6} +.card.bg-danger h1,.card.bg-danger h2,.card.bg-danger h3,.card.bg-danger h4,.card.bg-danger h5,.card.bg-danger h6,.card.bg-info h1,.card.bg-info h2,.card.bg-info h3,.card.bg-info h4,.card.bg-info h5,.card.bg-info h6,.card.bg-primary h1,.card.bg-primary h2,.card.bg-primary h3,.card.bg-primary h4,.card.bg-primary h5,.card.bg-primary h6,.card.bg-success h1,.card.bg-success h2,.card.bg-success h3,.card.bg-success h4,.card.bg-success h5,.card.bg-success h6,.card.bg-warning h1,.card.bg-warning h2,.card.bg-warning h3,.card.bg-warning h4,.card.bg-warning h5,.card.bg-warning h6{color:#fff} +.card.bg-danger p,.card.bg-info p,.card.bg-primary p,.card.bg-success p,.card.bg-warning p{color:#e6e6e6} +.card .card-heading{padding:15px 20px;position:relative} +.card .card-heading .card-title{margin-bottom:0} +.card .card-body{padding:15px 20px} +.card .card-footer{position:relative;padding:10px 15px;min-height:55px;background-color:transparent} +.card .card-footer .btn{margin:0}.card .card-footer .btn-flat{font-size:13px;text-transform:uppercase} +.card .card-horizon{padding:0;position:relative} +.card .card-horizon .image-container{overflow:hidden;position:absolute;height:100%;padding:0;top:0} +@media only screen and (max-width:767px){.card .card-horizon .image-container{position:static}} + +.card .card-horizon .card-body{position:relative} +.card .card-horizon .background-holder{position:relative;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:50%;background-repeat:no-repeat;z-index:0} +@media only screen and (max-width:767px){ + .card .card-horizon .background-holder{min-height:200px} +} +.card .card-horizon .background-holder.has-content{display:table} +.card .card-horizon .background-holder.has-content .content{display:table-cell;vertical-align:middle;padding:0 15px} +.card:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;z-index:2;visibility:hidden;opacity:0;background:#fff;background:hsla(0,0%,100%,.85);transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out} +.card-block{padding:30px}.portlet{position:absolute;top:0;right:0;z-index:1} +.portlet .portlet-item{list-style:none;padding:18px 20px} +.portlet .portlet-item>li{display:inline-block;margin-right:3px} +.portlet .portlet-item>li>a{margin-bottom:0;margin-right:0;padding:5px 6px;font-size:12px;line-height:1} +.portlet .dropdown-menu{transform-origin:top right;transform:scale(0);-webkit-transform:scale(0);-moz-transform:scale(0);-o-transform:scale(0);-ms-transform:scale(0);transition:transform .15s ease-out;-webkit-transition:transform .15s ease-out;-moz-transition:transform .15s ease-out;-o-transition:transform .15s ease-out;-ms-transition:transform .15s ease-out;display:block;margin:0;border-radius:0;left:auto;right:-10px}.portlet .show .dropdown-menu{transform:scale(1);-webkit-transform:scale(1);-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1)} +.card-title{font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;color:#333;margin-top:0;margin-bottom:15px}.card-media{position:relative} +.card-media img{width:100%}.card-refresh:before{visibility:visible;opacity:1} +.card-refresh:after{content:"";position:absolute;top:calc(50% - 20px);left:calc(50% - 20px);border:3px solid #e6ecf5;border-top:3px solid #7774e7;border-radius:50%;width:40px;height:40px;z-index:3;animation:spin 1.2s linear infinite;transform:translateX(-50%) translateY(-50%);-webkit-transform:translateX(-50%) translateY(-50%);-moz-transform:translateX(-50%) translateY(-50%);-o-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}} +a.card{display:block} +a.card:focus,a.card:hover{box-shadow:0 7px 15px rgba(0,0,0,.075)} + +.overlay-dark{position:relative;overflow:hidden;color:#ccc} +.overlay-dark h1,.overlay-dark h2,.overlay-dark h3,.overlay-dark h4,.overlay-dark h5,.overlay-dark h6{color:#fff} +.overlay-dark p{color:#ccc} +.overlay-dark:before{content:"";background-color:#333;position:absolute;width:100%;height:100%;opacity:.5;top:0;left:0;z-index:2} +.overlay-dark>div{position:relative;z-index:3}blockquote{border-left:0;padding-left:30px;position:relative} +blockquote:before{font-family:themify;content:"\E67F";position:absolute;left:0;color:#333}.fade.in{opacity:1} + +.bottom-0{bottom:0px!important} +.bottom-1{bottom:1px!important} +.bottom-2{bottom:2px!important} +.bottom-3{bottom:3px!important} +.bottom-4{bottom:4px!important} +.bottom-5{bottom:5px!important} +.bottom-6{bottom:6px!important} +.bottom-7{bottom:7px!important} +.bottom-8{bottom:8px!important} +.bottom-9{bottom:9px!important} +.bottom-10{bottom:10px!important} +.bottom-20{bottom:20px!important} +.bottom-30{bottom:30px!important} +.bottom-40{bottom:40px!important} +.bottom-50{bottom:50px!important} +.bottom-60{bottom:60px!important} +.bottom-70{bottom:70px!important} +.bottom-80{bottom:80px!important} +.bottom-90{bottom:90px!important} +.bottom-100{bottom:100px!important} + +.left-0{left:0px!important} +.left-1 {left:1px!important} +.left-2 {left:2px!important} +.left-3 {left:3px!important} +.left-4 {left:4px!important} +.left-5 {left:5px!important} +.left-6 {left:6px!important} +.left-7 {left:7px!important} +.left-8 {left:8px!important} +.left-9 {left:9px!important} +.left-10{left:10px!important} +.left-20{left:20px!important} +.left-30{left:30px!important} +.left-40{left:40px!important} +.left-50{left:50px!important} +.left-60{left:60px!important} +.left-70{left:70px!important} +.left-80{left:80px!important} +.left-90{left:90px!important} +.left-100{left:100px!important} + +.right-0{right:0px!important} +.right-1{right:1px!important} +.right-2{right:2px!important} +.right-3{right:3px!important} +.right-4{right:4px!important} +.right-5{right:5px!important} +.right-6{right:6px!important} +.right-7{right:7px!important} +.right-8{right:8px!important} +.right-9{right:9px!important} +.right-10{right:10px!important} +.right-20{right:20px!important} +.right-30{right:30px!important} +.right-40{right:40px!important} +.right-50{right:50px!important} +.right-60{right:60px!important} +.right-70{right:70px!important} +.right-80{right:80px!important} +.right-90{right:90px!important;} +.right-100{right:100px!important} + +.top-0{top:0px!important} +.top-1{top:1px!important} +.top-2{top:2px!important} +.top-3{top:3px!important} +.top-4{top:4px!important} +.top-5{top:5px!important} +.top-6{top:6px!important} +.top-7{top:7px!important} +.top-8{top:8px!important} +.top-9{top:9px!important} +.top-10{top:10px!important} +.top-20{top:20px!important} +.top-30{top:30px!important} +.top-40{top:40px!important} +.top-50{top:50px!important} +.top-60{top:60px!important} +.top-65{top:65px!important} +.top-70{top:70px!important} +.top-80{top:80px!important} +.top-90{top:90px!important} +.top-100{top:100px!important} + +.width-0{width:0} +.width-10{width:10%} +.width-15{width:15%} +.width-20{width:20%} +.width-25{width:25%} +.width-30{width:30%} +.width-35{width:35%} +.width-40{width:40%} +.width-45{width:45%} +.width-50{width:50%} +.width-55{width:55%} +.width-60{width:60%} +.width-65{width:65%} +.width-70{width:70%} +.width-75{width:75%} +.width-80{width:80%} +.width-85{width:85%} +.width-90{width:90%} +.width-95{width:95%} +.width-100{width:100%} + +.height-60{height:60%} +.height-65{height:65%} +.height-70{height:70%} +.height-75{height:75%} +.height-80{height:80%} +.height-85{height:85%} +.height-90{height:90%} +.height-95{height:95%} +.height-100{height:100%} +.full-height{min-height:100vh} + +.ls-0{letter-spacing:0!important} +.ls-0-5{letter-spacing:.5px!important} +.ls-1{letter-spacing:1px!important} +.ls-1-5{letter-spacing:1.5px!important} +.ls-2{letter-spacing:2px!important} +.ls-2-5{letter-spacing:2.5px!important} +.ls-3{letter-spacing:3px!important} +.ls-3-5{letter-spacing:3.5px!important} +.ls-4{letter-spacing:4px!important} +.ls-4-5{letter-spacing:4.5px!important} +.ls-5{letter-spacing:5px!important} +.ls-5-5{letter-spacing:5.5px!important} +.ls-6{letter-spacing:6px!important} +.ls-6-5{letter-spacing:6.5px!important} +.ls-7{letter-spacing:7px!important} +.ls-7-5{letter-spacing:7.5px!important} +.ls-8{letter-spacing:8px!important} +.ls-8-5{letter-spacing:8.5px!important} +.ls-9{letter-spacing:9px!important} +.ls-9-5{letter-spacing:9.5px!important} +.ls-10{letter-spacing:10px!important} +.ls-11{letter-spacing:11px!important} +.ls-12{letter-spacing:12px!important} +.ls-13{letter-spacing:13px!important} +.ls-14{letter-spacing:14px!important} +.ls-15{letter-spacing:15px!important} + +.lh-0{line-height:0!important} +.lh-0-5{line-height:.5!important} +.lh-1{line-height:1!important} +.lh-1-1{line-height:1.1!important} +.lh-1-2{line-height:1.2!important} +.lh-1-3{line-height:1.3!important} +.lh-1-4{line-height:1.4!important} +.lh-1-5{line-height:1.5!important} +.lh-1-6{line-height:1.6!important} +.lh-1-7{line-height:1.7!important} +.lh-1-8{line-height:1.8!important} +.lh-1-9{line-height:1.9!important} +.lh-2{line-height:2!important} +.lh-2-1{line-height:2.1!important} +.lh-2-2{line-height:2.2!important} +.lh-2-3{line-height:2.3!important} +.lh-2-4{line-height:2.4!important} +.lh-2-5{line-height:2.5!important} +.lh-3{line-height:3!important} +.lh-4{line-height:4!important} + +.font-size-8{font-size:8px!important} +.font-size-9{font-size:9px!important} +.font-size-10{font-size:10px!important} +.font-size-11{font-size:11px!important} +.font-size-12{font-size:12px!important} +.font-size-13{font-size:13px!important} +.font-size-14{font-size:14px!important} +.font-size-15{font-size:15px!important} +.font-size-16{font-size:16px!important} +.font-size-17{font-size:17px!important} +.font-size-18{font-size:18px!important} +.font-size-19{font-size:19px!important} +.font-size-20{font-size:20px!important} +.font-size-21{font-size:21px!important} +.font-size-22{font-size:22px!important} +.font-size-23{font-size:23px!important} +.font-size-24{font-size:24px!important} +.font-size-25{font-size:25px!important} +.font-size-26{font-size:26px!important} +.font-size-27{font-size:27px!important} +.font-size-28{font-size:28px!important} +.font-size-29{font-size:29px!important} +.font-size-30{font-size:30px!important} +.font-size-35{font-size:35px!important} +.font-size-40{font-size:40px!important} +.font-size-45{font-size:45px!important} +.font-size-50{font-size:50px!important} +.font-size-55{font-size:55px!important} +.font-size-60{font-size:60px!important} +.font-size-65{font-size:65px!important} +.font-size-70{font-size:70px!important} +.font-size-75{font-size:75px!important} +.font-size-80{font-size:80px!important} +.font-size-85{font-size:85px!important} +.font-size-90{font-size:90px!important} +.font-size-95{font-size:95px!important} +.font-size-100{font-size:100px!important} +.font-size-105{font-size:105px!important} +.font-size-110{font-size:110px!important} +.font-size-115{font-size:115px!important} +.font-size-120{font-size:120px!important} +.font-size-125{font-size:125px!important} +.font-size-130{font-size:130px!important} +.font-size-135{font-size:135px!important} +.font-size-140{font-size:140px!important} +.font-size-145{font-size:145px!important} +.font-size-150{font-size:150px!important} +.font-size-155{font-size:155px!important} +.font-size-160{font-size:160px!important} +.font-size-165{font-size:165px!important} +.font-size-170{font-size:170px!important} +.font-size-175{font-size:175px!important} +.font-size-180{font-size:180px!important} +.font-size-185{font-size:185px!important} +.font-size-190{font-size:190px!important} +.font-size-195{font-size:195px!important} +.font-size-200{font-size:200px!important} + +.text-light{font-weight:300!important} +.text-normal{font-weight:400!important} +.text-semibold{font-weight:500!important} +.text-bold{font-weight:700!important} + +.display-block{display:block!important} +.inline-block{display:inline-block!important} + +.pointer{cursor:pointer} + +.relative{position:relative} +.absolute{position:absolute} +.fixed{position:fixed} +.static{position:static} + +.overflow-hidden{overflow:hidden} +.overflow-y-hidden{overflow-y:hidden} +.overflow-x-hidden{overflow-x:hidden} +.overflow-auto{overflow:auto} +.overflow-y-auto{overflow-y:auto} +.overflow-x-auto{overflow-x:auto} + +.text-center{text-align:center!important} +.text-left{text-align:left!important} +.text-right{text-align:right!important} +.img-circle{border-radius:50%!important} + +.border{border:1px solid #e6ecf5} +.border.top{border:0!important;border-top:1px solid #e6ecf5!important} +.border.right{border:0!important;border-right:1px solid #e6ecf5!important} +.border.bottom{border:0!important;border-bottom:1px solid #e6ecf5!important} +.border.left{border:0!important;border-left:1px solid #e6ecf5!important} + +@media only screen and (max-width:992px){.border.border-hide-md{border:0!important}} +@media only screen and (max-width:767px){.border.border-hide-sm{border:0!important}} +.no-border{border:0!important;border-radius:0!important} + +@media only screen and (max-width:767px){ + .text-center-sm{text-align:center!important} + .text-left-sm{text-align:left!important} + .text-right-sm{text-align:right!important} +} +.vertical-align{display:table;height:100%;width:100%} +.vertical-align .table-cell{display:table-cell;vertical-align:middle} +.vertical-align-super{vertical-align:super} + +.border-radius-4{border-radius:4px!important} +.border-radius-6{border-radius:6px!important} +.border-radius-8{border-radius:8px!important} +.border-radius-10{border-radius:10px!important} +.border-radius-round{border-radius:50px!important} + +.side-nav{width:260px;background-color:#fff;z-index:1000;top:0;bottom:0;position:fixed;overflow:hidden;transition:all .2s ease;-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;-ms-transition:all .2s ease} +.header{display:block;height:65px;width:100%;position:fixed;padding:0;z-index:800;background-color:#fff;border-bottom:1px solid #e6ecf5;margin-bottom:0;transition:all .2s ease;-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;-ms-transition:all .2s ease} + +.header .header-container:after,.header .header-container:before{content:" ";display:table} +.header .header-container:after{clear:both} +.header .header-container .nav-left,.header .header-container .nav-right{position:relative;list-style:none;padding-left:0;margin-bottom:0} +.header .header-container .nav-left>li,.header .header-container .nav-right>li{float:left} +.header .header-container .nav-left>li>a,.header .header-container .nav-right>li>a{padding:0 15px;line-height:56px;min-height:56px;color:#333;display:block;transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out} +.header .header-container .nav-left>li>a i,.header .header-container .nav-right>li>a i{font-size:28px} +.header .header-container .nav-left>li>a:focus,.header .header-container .nav-left>li>a:hover,.header .header-container .nav-right>li>a:focus,.header .header-container .nav-right>li>a:hover{text-decoration:none;color:#333} +@media only screen and (max-width:992px){ + .header .header-container .nav-left>li>a,.header .header-container .nav-right>li>a{padding:0 15px} +} +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile,.header .header-container .nav-right .user-profile{border-right:0;border-left:0} +} +.header .header-container .nav-left .user-profile .profile-img,.header .header-container .nav-right .user-profile .profile-img{display:inline-block;width:35px;border-radius:50%;float:left} +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile .profile-img,.header .header-container .nav-right .user-profile .profile-img{width:30px;margin-right:0}} +.header .header-container .nav-left .user-profile .user-info,.header .header-container .nav-right .user-profile .user-info{display:inline-block} + +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile .user-info,.header .header-container .nav-right .user-profile .user-info{display: none}} +@media only screen and (max-width:992px){ + .header .header-container .nav-left .user-profile .user-info,.header .header-container .nav-right .user-profile .user-info.login-btn{display: block}} + +.header .header-container .nav-left .user-profile .dropdown-menu>li>a,.header .header-container .nav-right .user-profile .dropdown-menu>li>a{color:#333} +.header .header-container .nav-left .notifications,.header .header-container .nav-right .notifications{position:relative} +.header .header-container .nav-left .notifications .counter,.header .header-container .nav-right .notifications .counter{position:absolute;right:6px;top:12px;background-color:#ff3c7e;color:#fff;padding:3px 5.5px;border-radius:50px;line-height:1;font-size:10px} +.header .header-container .nav-left .notifications .dropdown-menu,.header .header-container .nav-right .notifications .dropdown-menu{min-width:350px;padding:0} +@media only screen and (max-width:767px){ + .header .header-container .nav-left .notifications .dropdown-menu,.header .header-container .nav-right .notifications .dropdown-menu{max-width:300px}} +.header .header-container .nav-left .notifications .dropdown-menu .list-info,.header .header-container .nav-right .notifications .dropdown-menu .list-info{max-height:248px;overflow-y:auto;position:relative} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a{padding:20px 15px;font-size:13px;display:block;border-bottom:1px solid #e6ecf5;transition:all .15s ease-out;-webkit-transition:all .15s ease-out;-moz-transition:all .15s ease-out;-o-transition:all .15s ease-out;-ms-transition:all .15s ease-out} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a:focus,.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a:hover,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a:focus,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a:hover{color:#333;text-decoration:none;background-color:#f6f7fb} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li>a .sub-title,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li>a .sub-title{padding-top:3px} +.header .header-container .nav-left .notifications .dropdown-menu .list-info>li:last-child a,.header .header-container .nav-right .notifications .dropdown-menu .list-info>li:last-child a{border-bottom:0} +.header .header-container .nav-left .notifications .dropdown-menu .notice-header,.header .header-container .nav-right .notifications .dropdown-menu .notice-header{padding:15px 20px;border-bottom:1px solid #e6ecf5} +.header .header-container .nav-left .notifications .dropdown-menu .notice-footer,.header .header-container .nav-right .notifications .dropdown-menu .notice-footer{text-align:center;padding:15px 20px;border-top:1px solid #e6ecf5} +.header .header-container .nav-left .notifications .dropdown-menu .notice-footer a,.header .header-container .nav-right .notifications .dropdown-menu .notice-footer a{display:block} +.header .header-container .nav-left .notifications .dropdown-menu.list-info,.header .header-container .nav-right .notifications .dropdown-menu.list-info{position:absolute}.header .header-container .dropdown-menu{-webkit-transform-origin:top right;transform-origin:top right;transform:scale(0);-webkit-transform:scale(0);-moz-transform:scale(0);-o-transform:scale(0);-ms-transform:scale(0);transition:transform .15s ease-out;-webkit-transition:transform .15s ease-out;-moz-transition:transform .15s ease-out;-o-transition:transform .15s ease-out;-ms-transition:transform .15s ease-out;display:block;margin:0} +.header .header-container .dropdown-menu .divider{border-bottom:1px solid #e6ecf5;height:1px;overflow:hidden}.header .header-container .dropdown-menu>li>a{transition:all .2s ease-out;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;-ms-transition:all .2s ease-out} +.header .header-container .show .dropdown-menu{transform:scale(1);-webkit-transform:scale(1);-moz-transform:scale(1);-o-transform:scale(1);-ms-transform:scale(1)} +.header .header-container .nav-left{float:left;margin-left:15px} +.header .header-container .nav-right{float:right} +.header .header-container .nav-right .dropdown-menu{left:auto;right:0} +.header .header-container .nav-right .dropdown-menu>li{width:100%} +.header .header-container .nav-right .dropdown-menu>li>a{line-height:1.5;min-height:auto;padding:10px 15px} +.header .search-box.active .search-icon,.header .search-box .search-icon-close{display:none} +.header .search-box.active .search-icon-close{display:inline-block} +.header .search-input{display:none} +.header .search-input.active{display:inline-block} +.header .search-input input{border:0;box-shadow:none;background-color:transparent;outline:none;height:40px;margin-top:12px;padding:5px;font-size:18px} + +@media only screen and (max-width:767px){.header .search-input input{width:85px}} +.header .search-input input::-webkit-input-placeholder{font-style:italic;color:#c3c5d3}.header .search-input input:-moz-placeholder,.header .search-input input::-moz-placeholder{font-style:italic;color:#c3c5d3}.header .search-input input:-ms-input-placeholder{font-style:italic;color:#c3c5d3}.header .search-input .advanced-search{display:none;position:absolute;top:59px;width:380px;min-height:50px;max-height:500px;background-color:#fff;border-radius:4px;box-shadow:0 0 8px 0 rgba(0,0,0,.2)} +@media only screen and (max-width:767px){.header .search-input .advanced-search{left:40px}} +.header .search-input .advanced-search.active{display:block}.header .search-input .advanced-search .search-wrapper{position:relative}.header .search-input .advanced-search .search-wrapper ul>li>a{padding:12px 20px}.header .search-input .advanced-search .search-wrapper ul>li>a:focus,.header .search-input .advanced-search .search-wrapper ul>li>a:hover{background-color:#f6f7fb}.header .search-input .search-footer{border-top:1px solid #e6ecf5;text-align:center;padding:15px;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.is-collapsed .header{width:100%} +@media only screen and (max-width:992px){.is-collapsed .header{width:100%}} + +.content-footer{padding:0 30px} +.content-footer .footer{padding:20px 0;font-size:90%;border-top:1px solid #e6ecf5} +.content-footer .footer .go-right{float:right} +.widget{position:relative;overflow:hidden} +.widget-news-1 .news-wrapper{background-repeat:no-repeat;background-size:cover;background-position:50%;min-height:400px;padding:15px} +.widget-news-1 .news-wrapper.wrapper-pdd-lg{padding:40px 120px} +.widget-news-1 .news-wrapper.wrapper-pdd-md{padding:30px 50px} +.widget-news-1 .news-wrapper.wrapper-pdd-sm{padding:30px} +.widget-news-1 .news-wrapper .user-thumbnail .user-img{display:inline-block;width:60px;border-radius:50%;float:left} +.widget-news-1 .news-wrapper .user-thumbnail .user-info{display:inline-block;margin-left:10px;color:#fff;padding-top:5px} +.widget-news-1 .news-wrapper .user-thumbnail .user-info .name{display:block;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;font-size:16px} +.widget-news-1 .news-wrapper .user-thumbnail .user-info .date{display:block;opacity:.8} +.widget-news-1 .news-wrapper .news-content{position:relative} +.widget-news-1 .news-wrapper .news-content .news-title{color:#fff;font-size:20px;margin-bottom:20px} +.widget-news-1 .news-wrapper .news-content .news-article{color:#ccc} +.widget-profile-1 .profile{text-align:center;padding:10px 20px} +.widget-profile-1 .profile img{border-radius:50%} +.widget-compose{padding:15px} +.widget-compose .composor-tools{padding-left:0;list-style:none} +.widget-compose .composor-tools>li{display:inline-block} +.widget-compose .composor-tools>li>a{display:block;font-weight:700;color:#333;padding:10px} +.widget-compose .composor-tools>li.active a,.widget-compose .composor-tools>li>a:focus,.widget-compose .composor-tools>li>a:hover{color:#333} +.widget-compose textarea.form-control{border:0;min-height:60px;padding:20px 10px} +.widget-feed{padding:25px 30px} +.widget-feed .feed-header{padding-bottom:10px} +.widget-feed .feed-body{padding:15px 0} +.widget-feed .feed-action{padding-left:0;list-style:none} +.widget-feed .feed-action>li{display:inline-block} +.widget-feed .feed-action>li>a{display:block;color:#333;font-size:16px;font-weight:500;padding:10px 25px 10px 0} +.widget-feed .feed-action>li.active a,.widget-feed .feed-action>li>a:focus,.widget-feed .feed-action>li>a:hover{color:#333} +.widget-feed .comment .comment-item{padding:30px 0;border-bottom:1px solid #e6ecf5} +.widget-feed .comment .add-comment textarea{min-height:50px;resize:none;border:0;padding:20px 10px 5px} +.widget-feed .comment .list-info .info{height:auto} +.widget-feed .comment .list-info .info p{margin-bottom:0} +.widget-feed .shared-item{position:relative;border:1px solid #e6ecf5;display:flex} +.widget-feed .shared-item .item-image{flex:4;width:30%} +.widget-feed .shared-item .item-content{flex:6;width:70%;padding:30px} +.widget-feed iframe{border:0;width:100%;min-height:300px} + +button{box-shadow:none;cursor:pointer} +button,button:focus{outline:none} +button.active:focus,button:active:focus{outline:none;box-shadow:none} +button.disabled,button:disabled{opacity:.5;cursor:not-allowed} +.btn{cursor:pointer;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;letter-spacing:1px;font-size:13px;padding:10px 20px;border-radius:6px;margin-right:5px;margin-bottom:10px;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out} +.btn.dropdown-toggle{margin-bottom:0} +.btn:focus{box-shadow:none} +.btn.active:focus,.btn:active:focus,.btn:focus{outline:none} +.btn-inverse{font-weight:700} +.btn-default{color:#333;background-color:#fff;border-color:#d4deee;font-weight:500} +.btn-default.active:focus,.btn-default.active:hover,.btn-default:active,.btn-default:active:focus,.btn-default:active:hover,.btn-default:focus,.btn-default:hover{color:#333;background-color:#edf2f8;border-color:#edf2f8} +.btn-primary{background-color:#7774e7;border-color:#7774e7;color:#fff} +.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#8c8aeb;border-color:#8c8aeb} +.btn-primary.active,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active{background-color:#625ee3;border-color:#625ee3} +.btn-primary.btn-inverse{background-color:#f7f6fe;color:#7774e7;border-color:transparent;box-shadow:none} +.btn-primary.btn-inverse:focus,.btn-primary.btn-inverse:hover{background-color:#e1e1fa;color:#625ee3;border-color:transparent} +.btn-primary.disabled{opacity:.35} +.btn-primary.disabled,.btn-primary.disabled:focus,.btn-primary.disabled:hover{background-color:#7774e7;border-color:#7774e7} +.btn-success{background-color:#37c936;border-color:#37c936;color:#fff} +.btn-success:focus,.btn-success:hover{color:#fff;background-color:#4bce4a;border-color:#4bce4a} +.btn-success.active,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active{background-color:#32b531;border-color:#32b531} +.btn-success.btn-inverse{background-color:#ebfaeb;color:#37c936;border-color:transparent;box-shadow:none} +.btn-success.btn-inverse:focus,.btn-success.btn-inverse:hover{background-color:#d7f4d7;color:#32b531;border-color:transparent} +.btn-success.disabled{opacity:.35}.btn-success.disabled,.btn-success.disabled:focus,.btn-success.disabled:hover{background-color:#37c936;border-color:#37c936} +.btn-info{background-color:#0f9aee;border-color:#0f9aee;color:#fff} +.btn-info:focus,.btn-info:hover{color:#fff;background-color:#25a4f1;border-color:#25a4f1} +.btn-info.active,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active{background-color:#0d8ad6;border-color:#0d8ad6} +.btn-info.btn-inverse{background-color:#e5f4fd;color:#0f9aee;border-color:transparent;box-shadow:none} +.btn-info.btn-inverse:focus,.btn-info.btn-inverse:hover{background-color:#cdeafc;color:#0d8ad6;border-color:transparent} +.btn-info.disabled{opacity:.35}.btn-info.disabled,.btn-info.disabled:focus,.btn-info.disabled:hover{background-color:#0f9aee;border-color:#0f9aee} +.btn-warning{color:#fff;background-color:#fc0;border-color:#fc0}.btn-warning:focus,.btn-warning:hover{color:#fff;background-color:#ffd11a;border-color:#ffd11a} +.btn-warning.active,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active{background-color:#e6b800;border-color:#e6b800} +.btn-warning.btn-inverse{background-color:#fffae6;color:#fc0;border-color:transparent;box-shadow:none} +.btn-warning.btn-inverse:focus,.btn-warning.btn-inverse:hover{background-color:#fff5cc;color:#e6b800;border-color:transparent} +.btn-warning.disabled{opacity:.35} +.btn-warning.disabled,.btn-warning.disabled:focus,.btn-warning.disabled:hover{background-color:#fc0;border-color:#fc0} +.btn-danger{color:#fff;background-color:#ff3c7e;border-color:#ff3c7e} +.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#ff568f;border-color:#ff568f} +.btn-danger.active,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active{background-color:#ff236d;border-color:#ff236d} +.btn-danger.btn-inverse{background-color:#ffeff4;color:#ff3c7e;border-color:transparent;box-shadow:none} +.btn-danger.btn-inverse:focus,.btn-danger.btn-inverse:hover{background-color:#ffd5e3;color:#ff236d;border-color:transparent} +.btn-danger.disabled{opacity:.35} +.btn-danger.disabled,.btn-danger.disabled:focus,.btn-danger.disabled:hover{background-color:#ff3c7e;border-color:#ff3c7e} +.show>.dropdown-toggle.btn-primary,.show>.dropdown-toggle.btn-primary:focus,.show>.dropdown-toggle.btn-primary:hover{background-color:#625ee3;border-color:#625ee3} +.show>.dropdown-toggle.btn-primary.btn-inverse,.show>.dropdown-toggle.btn-primary.btn-inverse:focus,.show>.dropdown-toggle.btn-primary.btn-inverse:hover{background-color:#e1e1fa;color:#625ee3} +.show>.dropdown-toggle.btn-success,.show>.dropdown-toggle.btn-success:focus,.show>.dropdown-toggle.btn-success:hover{background-color:#32b531;border-color:#32b531} +.show>.dropdown-toggle.btn-success.btn-inverse,.show>.dropdown-toggle.btn-success.btn-inverse:focus,.show>.dropdown-toggle.btn-success.btn-inverse:hover{background-color:#d7f4d7;color:#32b531} +.show>.dropdown-toggle.btn-info,.show>.dropdown-toggle.btn-info:focus,.show>.dropdown-toggle.btn-info:hover{background-color:#0d8ad6;border-color:#0d8ad6} +.show>.dropdown-toggle.btn-info.btn-inverse,.show>.dropdown-toggle.btn-info.btn-inverse:focus,.show>.dropdown-toggle.btn-info.btn-inverse:hover{background-color:#cdeafc;color:#0d8ad6} +.show>.dropdown-toggle.btn-warning,.show>.dropdown-toggle.btn-warning:focus,.show>.dropdown-toggle.btn-warning:hover{background-color:#e6b800;border-color:#e6b800} +.show>.dropdown-toggle.btn-warning.btn-inverse,.show>.dropdown-toggle.btn-warning.btn-inverse:focus,.show>.dropdown-toggle.btn-warning.btn-inverse:hover{background-color:#fff5cc;color:#e6b800} +.show>.dropdown-toggle.btn-danger,.show>.dropdown-toggle.btn-danger:focus,.show>.dropdown-toggle.btn-danger:hover{background-color:#ff236d;border-color:#ff236d} +.show>.dropdown-toggle.btn-danger.btn-inverse,.show>.dropdown-toggle.btn-danger.btn-inverse:focus,.show>.dropdown-toggle.btn-danger.btn-inverse:hover{background-color:#ffd5e3;color:#ff236d} + + +.page-title h1,.page-title h2,.page-title h3,.page-title h4,.page-title h5,.page-title h6,.page-title p,.page-title span{font-size:20px;font-family:Roboto,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Arial,sans-serif;margin-top:15px;margin-bottom:25px;margin-top:0} +.breadcrumb{padding:0 15px;margin-bottom:0;list-style:none;background-color:transparent;border-radius:0} +.dropdown .dropdown-menu{border:0;border-radius:5px} +.dropdown.right .dropdown-menu{left:auto;right:0} +.dropdown-menu{font-size:14px;box-shadow:0 2px 5px rgba(0,0,0,.2);top:100%} +.dropdown-menu>li.divider{background-color:#e6ecf5} +.dropdown-menu>li>a{line-height:1.5;min-height:auto;padding:10px 15px;display:block;transition:all .15s ease-out;-webkit-transition:all .15s ease-out;-moz-transition:all .15s ease-out;-o-transition:all .15s ease-out;-ms-transition:all .15s ease-out;color:#333} +.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#333;text-decoration:none;background-color:#f6f7fb} +.dropdown-toggle:after{border:0;display:none} + + + +.nav-tabs{border-bottom:1px solid #e6ecf5} +.nav-tabs>li{margin-bottom:-2px}.nav-tabs>li>a{margin-right:0;line-height:2;border-radius:0;color:#333;opacity:.75;border:0;border-bottom:2px solid transparent;display:block;padding:10px 15px;transition:all .3s ease-in-out;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out} +.nav-tabs>li>a:hover{border-color:transparent} +.nav-tabs>li>a:focus,.nav-tabs>li>a:hover{background-color:transparent;opacity:1} +.nav-tabs>li>a.active,.nav-tabs>li>a.active:focus,.nav-tabs>li>a.active:hover{border:0;background-color:transparent;border-bottom:2px solid #7774e7;opacity:1} +.nav-tabs>li>a.active.nav-link{border-bottom:2px solid #7774e7;color:#333;background-color:transparent} +.nav-tabs .nav-link{border-top:0;border-right:0;border-left:0} +.nav-tabs .nav-link:active,.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:transparent} +.tab-success .nav-tabs>li>a.active,.tab-success .nav-tabs>li>a.active:focus,.tab-success .nav-tabs>li>a.active:hover{border-bottom:2px solid #37c936} +.tab-info .nav-tabs>li>a.active,.tab-info .nav-tabs>li>a.active:focus,.tab-info .nav-tabs>li>a.active:hover{border-bottom:2px solid #0f9aee} +.tab-warning .nav-tabs>li>a.active,.tab-warning .nav-tabs>li>a.active:focus,.tab-warning .nav-tabs>li>a.active:hover{border-bottom:2px solid #fc0} +.tab-danger .nav-tabs>li>a.active,.tab-danger .nav-tabs>li>a.active:focus,.tab-danger .nav-tabs>li>a.active:hover{border-bottom:2px solid #ff3c7e} +.center-tabs .nav-tabs{text-align:center;-webkit-box-pack:center!important;-ms-flex-pack:center!important;justify-content:center!important} +.center-tabs .nav-tabs>li{float:none;display:inline-block}.justified-tabs .nav-tabs{width:100%} +.justified-tabs .nav-tabs>li{display:table-cell;width:1%;text-align:center;float:none} +.nav-pills>li+li{margin-left:5px} +.nav-pills>li>a{border-radius:3px;opacity:.75;font-size:14px;font-weight:500;background-color:transparent;color:#333;border:1px solid transparent;padding:5px 15px} +.nav-pills>li>a:focus,.nav-pills>li>a:hover{background-color:transparent;opacity:1} +.nav-pills>li>a.active,.nav-pills>li>a.active:focus,.nav-pills>li>a.active:hover{color:#fff;border-color:#7774e7;background-color:#7774e7;border:1px solid #7774e7;opacity:1} +.nav-pills>li>a.active.nav-link{color:#fff;background-color:#7774e7;border-color:#7774e7} +.nav-vertical .nav-pills{float:left;width:160px;padding:0 15px;display:block} +.nav-vertical .nav-pills>li{margin-bottom:15px} +.nav-vertical .nav-pills>li+li{margin-left:0} +.nav-vertical .tab-content{float:left;width:70%} +.pill-success .nav-pills>li>a.active,.pill-success .nav-pills>li>a.active:focus,.pill-success .nav-pills>li>a.active:hover{border-color:#37c936;background-color:#37c936;border:1px solid #37c936} +.pill-success .nav-pills>li>a.active.nav-link{color:#fff;border-color:#37c936} +.pill-info .nav-pills>li>a.active,.pill-info .nav-pills>li>a.active:focus,.pill-info .nav-pills>li>a.active:hover{border-color:#0f9aee;background-color:#0f9aee;border:1px solid #0f9aee} +.pill-info .nav-pills>li>a.active.nav-link{color:#fff;border-color:#0f9aee} +.pill-warning .nav-pills>li>a.active,.pill-warning .nav-pills>li>a.active:focus,.pill-warning .nav-pills>li>a.active:hover{border-color:#fc0;background-color:#fc0;border:1px solid #fc0} +.pill-warning .nav-pills>li>a.active.nav-link{color:#fff;border-color:#fc0} +.pill-danger .nav-pills>li>a.active,.pill-danger .nav-pills>li>a.active:focus,.pill-danger .nav-pills>li>a.active:hover{border-color:#ff3c7e;background-color:#ff3c7e;border:1px solid #ff3c7e} +.pill-danger .nav-pills>li>a.active.nav-link{color:#fff;border-color:#ff3c7e} +.accordion .panel-group{margin-bottom:20px} +.accordion .panel-default{background-color:#fff;margin-bottom:15px;border:1px solid #e6ecf5} +.accordion .panel-default>.panel-heading{color:#333;background-color:#fff;border-color:#e6ecf5} +.accordion .panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#e6ecf5;padding:10px 20px 20px} +.accordion.border-less .panel-default{border:0;border-bottom:1px solid #e6ecf5;margin-bottom:0} +.accordion .panel-heading{padding:0;border-bottom:0;border-top-left-radius:0;border-top-right-radius:0} +.accordion .panel-title{margin:0}.accordion .panel-title>a{padding:20px;display:block;color:#333} +.accordion .panel-title>a .icon{float:right;margin-top:5px;transform:rotate(0deg);-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-ms-transform:rotate(0deg);transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;-ms-transition:all .2s ease-in-out} +.accordion .panel-title>a.collapsed .icon{transform:rotate(-90deg);-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-o-transform:rotate(-90deg);-ms-transform:rotate(-90deg)} +.accordion .panel-title>a:focus,.accordion .panel-title>a:hover{text-decoration:none} + +.progress{height:4px;background-color:#eaeef3;border-radius:4px;margin-bottom:10px} +.progress.progress-sm{height:8px} +.progress.progress-md{height:15px} +.progress.progress-lg{height:20px} +.progress-bar{background-color:#333} +.progress-primary .progress-bar{background-color:#7774e7} +.progress-success .progress-bar{background-color:#37c936} +.progress-info .progress-bar{background-color:#0f9aee} +.progress-warning .progress-bar{background-color:#fc0} +.progress-danger .progress-bar{background-color:#ff3c7e} + +.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{line-height:1.8;border-color:#e6ecf5} +.table-sm>tbody>tr>td,.table-sm>tbody>tr>th,.table-sm>tfoot>tr>td,.table-sm>tfoot>tr>th,.table-sm>thead>tr>td,.table-sm>thead>tr>th{padding:5px} +.table-lg>tbody>tr>td,.table-lg>tbody>tr>th,.table-lg>tfoot>tr>td,.table-lg>tfoot>tr>th,.table-lg>thead>tr>td,.table-lg>thead>tr>th{padding:15px} +.table-xl>tbody>tr>td,.table-xl>tbody>tr>th,.table-xl>tfoot>tr>td,.table-xl>tfoot>tr>th,.table-xl>thead>tr>td,.table-xl>thead>tr>th{padding:20px} +.table-striped>tbody>tr:nth-of-type(odd){background-color:#fbfcfd} +.table-hover>tbody>tr:hover{background-color:#f6f7fb}.table-bordered{border:1px solid #e6ecf5}.table>thead>tr>th{color:#333;border-bottom:1px solid #e6ecf5} +@media only screen and (max-width:992px){.table-overflow{width:100%;overflow-x:auto}} + +.form-wizard .nav-pills{position:relative}.form-wizard .nav-pills>li>a{z-index:1;opacity:1;position:relative;display:block} +.form-wizard .nav-pills>li>a .step{width:36px;line-height:28px;height:36px;border-radius:50%;border:4px solid #e6ecf5;background:#fff;color:#333;display:inline-block} +.form-wizard .nav-pills>li>a .title{position:absolute;width:100%;left:0;bottom:-20px} +.form-wizard .nav-pills>li>a.active{background-color:transparent;border-color:transparent;color:#333} +.form-wizard .nav-pills>li>a.active .step{background-color:#0f9aee;border-color:#0f9aee;color:#fff} +.form-wizard .progress{position:absolute;display:inline-block;top:24px;left:0;right:0;margin:auto;height:5px;border-radius:0} +.form-wizard .tab-content{margin-top:90px;margin-bottom:30px} + +.page-container {min-width: 375px!important;} +@media print {.page-container {padding-left: 0px;}} +@media only screen and (min-width: 992px) and (max-width: 1440px) {.page-container{padding-left: 0px;}} +@media only screen and (max-width: 992px) {.page-container {padding-left: 0px;}} +.page-container .main-content {min-height: calc(100vh - 65px);} +@media print {.page-container .main-content {padding: 10px 0px;}} +.full-container {position: absolute; top: 65px; left: 250px; right: 0px; min-height: calc(100vh - 65px); transition: all 0.2s ease; -webkit-transition: all 0.2s ease; -moz-transition: all 0.2s ease; -o-transition: all 0.2s ease; -ms-transition: all 0.2s ease;} +@media only screen and (min-width: 992px) and (max-width: 1440px) {.full-container {padding-left: 0px; left: 0px;}} +@media only screen and (max-width: 992px) {.full-container {left: 0px;}} +.is-collapsed .page-container {padding-left: 0px;} + + +.video-container { + position: relative; + height: 0; + overflow: hidden; +} + +.video-container iframe{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.video-container-16x9 {padding-bottom: 56.25%;} +.video-container-4x3 {padding-bottom: 75%;} + +.none-background { + background-color: rgba(255,255,255,0) !important; +} + +.btn-green {background-color: darkseagreen;} + +.btn-kakaotalk { + background-color: #fae100; + color: #3c1e1e; +} + +.btn-kakaotalk:hover, .btn-kakaotalk:focus { + background-color: #faefa3; + border-color: #faefa3; + color: #3c1e1e; +} + +.bg-aliceblue {background-color: aliceblue !important;} +.bg-lightblue {background-color: lightblue !important;} +.bg-darkseagreen {background-color: darkseagreen !important;} +.bg-bisque {background-color: bisque !important;} +.bg-gray {background-color: gray !important;} +.bg-whitesmoke {background-color: whitesmoke !important;} +.bg-f8 {background-color: #f8f8f8; !important;} +.bg-gainsboro {background-color: gainsboro;} + +.width-auto {width: auto !important;} +.width-25px {width: 25px !important;} +.width-30px {width: 30px !important;} +.width-40px {width: 40px !important;} +.width-50px {width: 50px !important;} +.width-100px {width: 100px !important;} +.width-160px {width: 160px !important;} +.width-250 {width: 250px !important;} +.width-400 {width: 400px !important;} + +.max-width-80 {max-width: 80%; !important;} + +.min-width-480px {min-width: 480px !important;} +.min-width-992px {min-width: 992px !important;} + +.max-width-100 {max-width: 100% !important;} +.max-width-200px {max-width: 200px !important;} +.max-width-250px {max-width: 250px !important;} + +.max-width-lg {max-width: 1000px !important;} + +.height-25px {height: 25px !important;} +.height-30px {height: 30px !important;} +.height-40px {height: 40px !important;} +.height-50px {height: 50px !important;} + +.height-70vh {height: 70vh;} +.height-90vh {height: 90vh;} +.height-100vh {height: 100vh !important;} +.height-100vh-65px {height: calc(100vh - 65px);} +.height-100vh-160px {height: calc(100vh - 160px);} + +.min-height-5px {min-height: 5px !important;} +.min-height-460px {min-height: 460px !important;} +.min-height-130px {min-height: 130px !important;} +.min-height-150px {min-height: 150px !important;} +.min-height-180px {min-height: 180px !important;} +.min-height-200px {min-height: 200px !important;} + +.max-height-95 {max-height: 90% !important;} +.max-height-95 {max-height: 95% !important;} +.max-height-100 {max-height: 100% !important;} + +.max-height-200px {max-height: 200px;} +.max-height-250px {max-height: 250px;} +.max-height-300px {max-height: 300px;} +.max-height-450px {max-height: 450px;} + +.max-height-60vh {max-height: 60vh !important;} +.max-height-100vh-65px { max-height: calc(100vh - 65px); } +.max-height-100vh-100px {max-height: calc(100vh - 100px);} +.max-height-100vh-180px {max-height: calc(100vh - 180px);} + +.border-bottom-none {border-bottom: none !important;} +.border-bottom-radius { + border-bottom-right-radius: 5px !important; + border-bottom-left-radius: 5px !important; +} +.border-radius-none {border-radius: 0 !important;} + +.border-top-gainsboro {border-top: 1px solid gainsboro;} +.border-bottom-gainsboro {border-bottom: 1px solid gainsboro;} + +.border-left-5-gray {border-left: 5px solid gray;} +.border-left-5-green {border-left: 5px solid #37c936;} +.border-left-5-gainsboro {border-left: 5px solid gainsboro;} +.border-left-5-yellow {border-left: 5px solid #ffcc00;} + +.border-left-1 {border-left: 1px solid;} +.border-left-2 {border-left: 2px solid;} +.border-left-3 {border-left: 3px solid;} +.border-left-4 {border-left: 4px solid;} +.border-left-5 {border-left: 5px solid;} + +.border-bottom-1 {border-bottom: 1px solid;} +.border-bottom-2 {border-bottom: 2px solid;} +.border-bottom-3 {border-bottom: 3px solid;} +.border-bottom-4 {border-bottom: 4px solid;} +.border-bottom-5 {border-bottom: 5px solid;} + +.border-top-1 {border-top: 1px solid;} +.border-top-2 {border-top: 2px solid;} +.border-top-3 {border-top: 3px solid;} +.border-top-4 {border-top: 4px solid;} +.border-top-5 {border-top: 5px solid;} + +.border-radius-btm-round { + border-top-right-radius: 0px; + border-top-left-radius: 0px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} + +.z-1 {z-index: 1 !important;} +.z-10 {z-index: 10 !important;} +.z-800 {z-index: 800 !important;} +.z-1000 {z-index: 1000 !important;} + +.tag-gainsboro{background-color:gainsboro;color:#fff} +.tag-yellow{background-color:#fc0;color:#fff} +.tag-success{background-color:#37c936;color:#fff} +.tag-gray{background-color:gray;color:#fff} + +.visibility-hidden {visibility: hidden !important;} +.list-style-none {list-style: none;} + +.pace { + -webkit-pointer-events: none; + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.pace-inactive { + display: none; +} + +.pace .pace-progress { + background: #2299dd; + position: fixed; + z-index: 2000; + top: 0; + right: 100%; + width: 100%; + height: 2px; +} + +.justify-content-center {justify-content: center;} +.align-items-center {align-items: center;} + +.text-overflow { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css new file mode 100644 index 000000000..0f68b6bb9 --- /dev/null +++ b/src/main/resources/static/css/index.css @@ -0,0 +1,68 @@ +@media only screen and (min-width: 480px) { + .mobile-view { + display: none; + } + + .desktop-view { + display: block; + } +} + +@media only screen and (max-width: 480px) { + .mobile-view { + display: block; + } + + .desktop-view { + display: none; + } +} + +header ul.nav-right li, header ul.nav-left li { + height: 76px; +} + +.header { + background-color: white; + padding: 0 16px; + height: 76px; + top: 0px; +} + +.logo { + width: 170px; + height: auto; + line-height: 76px; + position: relative; +} + +.user-profile { + height: 43px; +} + +.profile-img { + width: 24px; + height: 24px; +} + +.add-comment textarea::placeholder { + color: #666; +} + +.mini-profile-img { + width: 20px; + height: 20px; + border-radius: 50%; +} + +.activated-heart { + color:#ed4956; +} + +.hashtag { + color: #003569; +} + +.search-input .advanced-search .search-wrapper .search-result-item { + height: 40px; +} diff --git a/src/main/resources/static/css/zzazan.css b/src/main/resources/static/css/zzazan.css new file mode 100644 index 000000000..16ba8f30a --- /dev/null +++ b/src/main/resources/static/css/zzazan.css @@ -0,0 +1,62 @@ +#zzazanstagram { + background-image: url("https://www.instagram.com/static/images/homepage/home-phones@2x.png/9364675fb26a.png"); + background-repeat:no-repeat; + background-size: contain; + width: 454px; + height: 618px; +} + +#main-carousel-slide { + width: 244px; + margin: 96px 0 0 149px; +} + +#signup-greeting-message { + margin: 20px 0 0 40px; +} + +#login-card { + width: 350px; +} + +#signup-card { + width: 350px; +} + +#login-card-submit-btn { + width: 308px; + height: 30px; + font-size: 12px; + padding: 0; +} + +#signup-card-submit-btn { + width: 308px; + height: 30px; + font-size: 12px; + padding: 0; +} + +#login-to-signup-card { + width: 350px; + margin-top: 390px; +} + +#signup-to-login-card { + width: 350px; + margin-top: 590px; +} + +.float-left { + float: left; +} + +.float-right { + float: right; +} + +.clear-none { + clear: none; +} + + diff --git a/src/main/resources/static/images/default/eastjun_big.jpg b/src/main/resources/static/images/default/eastjun_big.jpg new file mode 100644 index 000000000..a2af1244e Binary files /dev/null and b/src/main/resources/static/images/default/eastjun_big.jpg differ diff --git a/src/main/resources/static/images/default/eastjun_profile.jpg b/src/main/resources/static/images/default/eastjun_profile.jpg new file mode 100644 index 000000000..300cca23d Binary files /dev/null and b/src/main/resources/static/images/default/eastjun_profile.jpg differ diff --git a/src/main/resources/static/images/default/sample_img_01.jpg b/src/main/resources/static/images/default/sample_img_01.jpg new file mode 100644 index 000000000..e66c0cb51 Binary files /dev/null and b/src/main/resources/static/images/default/sample_img_01.jpg differ diff --git a/src/main/resources/static/images/default/sample_img_02.jpg b/src/main/resources/static/images/default/sample_img_02.jpg new file mode 100644 index 000000000..c82538144 Binary files /dev/null and b/src/main/resources/static/images/default/sample_img_02.jpg differ diff --git a/src/main/resources/static/images/default/zzazanstagram_main1.jpg b/src/main/resources/static/images/default/zzazanstagram_main1.jpg new file mode 100644 index 000000000..4b00e1e3f Binary files /dev/null and b/src/main/resources/static/images/default/zzazanstagram_main1.jpg differ diff --git a/src/main/resources/static/images/default/zzazanstagram_main2.jpg b/src/main/resources/static/images/default/zzazanstagram_main2.jpg new file mode 100644 index 000000000..843c128fe Binary files /dev/null and b/src/main/resources/static/images/default/zzazanstagram_main2.jpg differ diff --git a/src/main/resources/static/images/default/zzazanstagram_main3.jpg b/src/main/resources/static/images/default/zzazanstagram_main3.jpg new file mode 100644 index 000000000..99c48f3e0 Binary files /dev/null and b/src/main/resources/static/images/default/zzazanstagram_main3.jpg differ diff --git a/src/main/resources/static/images/default/zzazanstagram_main4.jpg b/src/main/resources/static/images/default/zzazanstagram_main4.jpg new file mode 100644 index 000000000..438b0d7f1 Binary files /dev/null and b/src/main/resources/static/images/default/zzazanstagram_main4.jpg differ diff --git a/src/main/resources/static/images/logo/favicon.ico b/src/main/resources/static/images/logo/favicon.ico new file mode 100644 index 000000000..10421396a Binary files /dev/null and b/src/main/resources/static/images/logo/favicon.ico differ diff --git a/src/main/resources/static/images/logo/instgram_logo.png b/src/main/resources/static/images/logo/instgram_logo.png new file mode 100644 index 000000000..efb13507e Binary files /dev/null and b/src/main/resources/static/images/logo/instgram_logo.png differ diff --git a/src/main/resources/static/images/logo/logo_thumnail_bg.jpg b/src/main/resources/static/images/logo/logo_thumnail_bg.jpg new file mode 100644 index 000000000..2485ae4b6 Binary files /dev/null and b/src/main/resources/static/images/logo/logo_thumnail_bg.jpg differ diff --git a/src/main/resources/static/images/logo/zzazanstagram.png b/src/main/resources/static/images/logo/zzazanstagram.png new file mode 100644 index 000000000..ee9d4095c Binary files /dev/null and b/src/main/resources/static/images/logo/zzazanstagram.png differ diff --git a/src/main/resources/templates/article-edit.html b/src/main/resources/templates/article-edit.html new file mode 100644 index 000000000..d4d964728 --- /dev/null +++ b/src/main/resources/templates/article-edit.html @@ -0,0 +1,150 @@ + + + + + + woostagram + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+
+ +
+ +
+
    +
  • + +
    +

    +

    새 글 쓰기

    +
    +
  • +
+
+
+
+
+ + + +
+ +
+
+ +
+
+ +
+ +
+
+
+
+
+
+
+ + + + + + + + diff --git a/src/main/resources/templates/fragments/empty.txt b/src/main/resources/templates/fragments/empty.txt new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 000000000..495d14b28 --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,205 @@ + + + + + + woostagram + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+ +
+
+ +
+
+ +
+ + + +
+ + +
+
+
+
+
+
+ + + + + + + + diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 000000000..14b30ab5b --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,106 @@ + + + + + + woostagram + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+ +
+
+
+ 계정이 없으신가요? + +
+
+
+ +
+
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 000000000..5c0872b8e --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,178 @@ + + + + + + woostagram + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ +
+ +
+
+ +
친구들의 사진을 보려면 가입하세요 :)
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+ +
+
+
+ 계정이 있으신가요? + +
+
+
+ +
+
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/ZzazanstagramApplicationTests.java b/src/test/java/com/woowacourse/zzazanstagram/ZzazanstagramApplicationTests.java new file mode 100644 index 000000000..731ed12de --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/ZzazanstagramApplicationTests.java @@ -0,0 +1,16 @@ +package com.woowacourse.zzazanstagram; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ZzazanstagramApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/RequestTemplate.java b/src/test/java/com/woowacourse/zzazanstagram/model/RequestTemplate.java new file mode 100644 index 000000000..2f853af17 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/RequestTemplate.java @@ -0,0 +1,66 @@ +package com.woowacourse.zzazanstagram.model; + +import com.woowacourse.zzazanstagram.model.support.WebTestHelper; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.reactive.server.WebTestClient; + +import static com.woowacourse.zzazanstagram.model.support.WebTestHelper.loginForm; + +@ActiveProfiles("test") +@AutoConfigureWebTestClient +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public abstract class RequestTemplate { + private static String email; + + @Autowired + public WebTestClient webTestClient; + + @BeforeEach + void setUp() { + if (email == null) { + webTestClient.post().uri("/members") + .body(WebTestHelper.userSignUpForm("test@gmail.com", + "myName", + "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg", + "myNick", + "Password!1")) + .exchange(); + email = "test@gmail.com"; + } + } + + public WebTestClient.RequestHeadersSpec getHeaderWithLogin(String uri) { + return webTestClient.get() + .uri(uri) + .header("Cookie", getCookie()); + } + + public WebTestClient.RequestBodySpec postHeaderWithLogin(String uri) { + return webTestClient.post() + .uri(uri) + .header("Cookie", getCookie()); + } + + public WebTestClient.RequestHeadersSpec getRequest(String url) { + return webTestClient.get().uri(url); + } + + public WebTestClient.RequestBodySpec postRequest(String url) { + return webTestClient.post().uri(url); + } + + private String getCookie() { + return webTestClient.post().uri("/login") + .body(loginForm("test@gmail.com", "Password!1")) + .exchange() + .expectStatus() + .isFound() + .returnResult(String.class) + .getResponseHeaders() + .getFirst("Set-Cookie"); + } +} diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java b/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java new file mode 100644 index 000000000..26fd9e9d2 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java @@ -0,0 +1,7 @@ +package com.woowacourse.zzazanstagram.model.article; + +public class ArticleConstant { + public static final String IMAGE_URL = "https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg"; + public static final String CONTENTS = "글의 내용이란다"; + public static final String HASHTAG = "#아이크 #닉 #뚱이 #제이 #에헴"; +} diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/article/controller/ArticleControllerTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/article/controller/ArticleControllerTest.java new file mode 100644 index 000000000..a4dc72c24 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/article/controller/ArticleControllerTest.java @@ -0,0 +1,55 @@ +package com.woowacourse.zzazanstagram.model.article.controller; + +import com.woowacourse.zzazanstagram.model.RequestTemplate; +import org.junit.jupiter.api.Test; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.BodyInserters; + +import static com.woowacourse.zzazanstagram.model.article.ArticleConstant.*; +import static org.assertj.core.api.Assertions.assertThat; + +class ArticleControllerTest extends RequestTemplate { + + @Test + void 게시글_등록_페이지_이동_테스트() { + getHeaderWithLogin("/articles/new") + .exchange() + .expectStatus().isOk(); + } + + @Test + void 게시글_등록이_되는지_테스트() { + createArticle() + .expectStatus().is3xxRedirection() + .expectHeader().valueMatches("Location", "http://[\\w\\d\\.]+:[0-9]+/"); + } + + @Test + void 게시글_조회_페이지_이동_테스트() { + showArticles(); + } + + @Test + void 게시글_조회가_잘되는지_테스트() { + createArticle(); + + showArticles().expectBody().consumeWith(res -> { + String body = new String(res.getResponseBody()); + assertThat(body.contains(IMAGE_URL)).isTrue(); + }); + } + + private WebTestClient.ResponseSpec showArticles() { + return getHeaderWithLogin("/") + .exchange() + .expectStatus().isOk(); + } + + private WebTestClient.ResponseSpec createArticle() { + return postHeaderWithLogin("/articles") + .body(BodyInserters.fromFormData("image", IMAGE_URL) + .with("contents", CONTENTS) + .with("hashTag", HASHTAG)) + .exchange(); + } +} \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/article/domain/ArticleTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/article/domain/ArticleTest.java new file mode 100644 index 000000000..d38570d06 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/article/domain/ArticleTest.java @@ -0,0 +1,37 @@ +package com.woowacourse.zzazanstagram.model.article.domain; + +import com.woowacourse.zzazanstagram.model.article.domain.vo.Contents; +import com.woowacourse.zzazanstagram.model.article.domain.vo.Image; +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static com.woowacourse.zzazanstagram.model.article.ArticleConstant.CONTENTS; +import static com.woowacourse.zzazanstagram.model.article.ArticleConstant.IMAGE_URL; +import static org.assertj.core.api.Assertions.assertThat; + +class ArticleTest { + private Image image; + private Contents contents; + private Article article; + private Member author; + + @BeforeEach + void setUp() { + image = Image.of(IMAGE_URL); + contents = Contents.of(CONTENTS); + author = Member.MemberBuilder.aMember() + .nickName("nickName") + .name("name") + .email("test@test.com") + .password("password1!") + .profile("https://image.shutterstock.com/image-photo/600w-1029171697.jpg") + .build(); + article = new Article(image, contents, author); + } + + @Test + void Article_객체_생성() { + assertThat(article).isEqualTo(new Article(image, contents, author)); + } +} \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/member/controller/MemberControllerTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/member/controller/MemberControllerTest.java new file mode 100644 index 000000000..9ecabdf9c --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/member/controller/MemberControllerTest.java @@ -0,0 +1,93 @@ +package com.woowacourse.zzazanstagram.model.member.controller; + +import com.woowacourse.zzazanstagram.model.RequestTemplate; +import com.woowacourse.zzazanstagram.model.support.WebTestHelper; +import org.junit.jupiter.api.Test; + +class MemberControllerTest extends RequestTemplate { + private static final String URL_REGEX = "https?://[.\\d\\w]+:?\\d*"; + private static final String JSESSIONID_URL = ";jsessionid=([\\d\\w]+)"; + + @Test + void 회원가입_페이지_이동() { + getRequest("/signup") + .exchange() + .expectStatus().isOk(); + } + + @Test + void 로그인_페이지_이동() { + getRequest("/login") + .exchange() + .expectStatus().isOk(); + } + + @Test + void 회원가입_성공() { + postRequest("/members") + .body(WebTestHelper.userSignUpForm("test2@gmail.com", + "myName", + "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg", + "myNick2", + "Password!1")) + .exchange() + .expectHeader().valueMatches("location", URL_REGEX + "/login") + .expectStatus().is3xxRedirection(); + } + + @Test + void 회원가입_실패_이메일_중복() { + postRequest("/members") + .body(WebTestHelper.userSignUpForm("test@gmail.com", + "myName", + "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg", + "myNick2", + "Password!1")) + .exchange() + .expectHeader().valueMatches("location", URL_REGEX + "/signup") + .expectStatus().is3xxRedirection(); + } + + @Test + void 회원가입_실패_닉네임_중복() { + postRequest("/members") + .body(WebTestHelper.userSignUpForm("test3@gmail.com", + "myName", + "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg", + "myNick", + "Password!1")) + .exchange() + .expectHeader().valueMatches("location", URL_REGEX + "/signup") + .expectStatus().is3xxRedirection(); + } + + @Test + void 로그인_성공() { + postRequest("/login") + .body(WebTestHelper.loginForm("test@gmail.com", + "Password!1")) + .exchange() + .expectHeader().valueMatches("location", URL_REGEX + "/" + JSESSIONID_URL) + .expectStatus().is3xxRedirection(); + } + + @Test + void 로그인_실패_존재하지_않는_이메일() { + postRequest("/login") + .body(WebTestHelper.loginForm("test10@gmail.com", + "Password!1")) + .exchange() + .expectHeader().valueMatches("location", URL_REGEX + "/login" + JSESSIONID_URL) + .expectStatus().is3xxRedirection(); + } + + @Test + void 로그인_실패_일치하지_않는_비밀번호() { + postRequest("/login") + .body(WebTestHelper.loginForm("test@gmail.com", + "Password@2")) + .exchange() + .expectHeader().valueMatches("location", URL_REGEX + "/login" + JSESSIONID_URL) + .expectStatus().is3xxRedirection(); + } +} \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/member/domain/MemberTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/member/domain/MemberTest.java new file mode 100644 index 000000000..76fcca4fe --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/member/domain/MemberTest.java @@ -0,0 +1,88 @@ +package com.woowacourse.zzazanstagram.model.member.domain; + +import com.woowacourse.zzazanstagram.model.member.domain.vo.Password; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class MemberTest { + @ParameterizedTest + @ValueSource(strings = {"1", "11111111111"}) + void 닉네임_비정상_체크(String nickName) { + assertThrows(IllegalArgumentException.class, () -> + Member.MemberBuilder.aMember().nickName(nickName)); + } + + @ParameterizedTest + @ValueSource(strings = {"name", "nick"}) + void 닉네임_정상_체크(String nickName) { + assertThatCode(() -> + Member.MemberBuilder.aMember().nickName(nickName)) + .doesNotThrowAnyException(); + } + + @ParameterizedTest + @ValueSource(strings = {"1", "11111111111"}) + void 이름_비정상_체크(String name) { + assertThrows(IllegalArgumentException.class, () -> + Member.MemberBuilder.aMember().name(name)); + } + + @ParameterizedTest + @ValueSource(strings = {"name", "nicky"}) + void 이름_정상_체크(String name) { + assertThatCode(() -> + Member.MemberBuilder.aMember().name(name)) + .doesNotThrowAnyException(); + } + + @ParameterizedTest + @ValueSource(strings = {"dfsdfsdf", "email@"}) + void 이메일_비정상_체크(String email) { + assertThrows(IllegalArgumentException.class, () -> + Member.MemberBuilder.aMember().email(email)); + } + + @ParameterizedTest + @ValueSource(strings = {"test@gmail.com", "dfsdfsdf@naver.com"}) + void 이메일_정상_체크(String email) { + assertThatCode(() -> + Member.MemberBuilder.aMember().email(email)) + .doesNotThrowAnyException(); + } + + @ParameterizedTest + @ValueSource(strings = {"dfdf", "dfsf/!", "DDff"}) + void 비밀번호_비정상_체크(String password) { + assertThrows(IllegalArgumentException.class, () -> + Member.MemberBuilder.aMember().password(password)); + } + + @ParameterizedTest + @ValueSource(strings = {"Password!1", "dffDzzzF2!"}) + void 비밀번호_정상_체크(String password) { + assertThatCode(() -> + Member.MemberBuilder.aMember().password(password)) + .doesNotThrowAnyException(); + } + + @Test + void 원문과_암호화된_비밀번호_비교() { + String input = "Password!1"; + Password password = Password.of(input); + assertThat(password.isMatch(input)).isTrue(); + } + + @ParameterizedTest + @ValueSource(strings = {"https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg", + "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg"}) + void 프로필_url_정상_체크(String profile) { + assertThatCode(() -> + Member.MemberBuilder.aMember().profile(profile)) + .doesNotThrowAnyException(); + } +} \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/support/WebTestHelper.java b/src/test/java/com/woowacourse/zzazanstagram/model/support/WebTestHelper.java new file mode 100644 index 000000000..ea58330a4 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/support/WebTestHelper.java @@ -0,0 +1,20 @@ +package com.woowacourse.zzazanstagram.model.support; + +import org.springframework.web.reactive.function.BodyInserters; + +import static org.springframework.web.reactive.function.BodyInserters.fromFormData; + +public class WebTestHelper { + public static BodyInserters.FormInserter userSignUpForm(String email, String name, String profile, String nickName, String password) { + return fromFormData("email", email) + .with("name", name) + .with("profile", profile) + .with("nickName", nickName) + .with("password", password); + } + + public static BodyInserters.FormInserter loginForm(String email, String password) { + return fromFormData("email", email) + .with("password", password); + } +}