initial commit
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="optional" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
<attribute name="optional" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v7.0"/>
|
||||
<classpathentry kind="src" path="target/generated-sources/annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="m2e-apt" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="m2e-apt" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_DISABLED_BUILDER" value="org.eclipse.wst.jsdt.core.javascriptValidator"/>
|
||||
<mapAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
</launchConfiguration>
|
||||
@@ -0,0 +1,98 @@
|
||||
<factorypath>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/projectlombok/lombok/1.18.32/lombok-1.18.32.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/4.3.25.RELEASE/spring-context-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/4.3.25.RELEASE/spring-expression-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-web/4.3.25.RELEASE/spring-web-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-webmvc/4.3.25.RELEASE/spring-webmvc-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/4.3.25.RELEASE/spring-aop-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/4.3.25.RELEASE/spring-beans-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context-support/4.3.25.RELEASE/spring-context-support-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/4.3.25.RELEASE/spring-core-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jdbc/4.3.25.RELEASE/spring-jdbc-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-tx/4.3.25.RELEASE/spring-tx-4.3.25.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/nexacro/nexacro17-xapi/1.0/nexacro17-xapi-1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/nexacro/nexacro-xapi/1.0/nexacro-xapi-1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/tobesoft/xplatform-xapi/1.0/xplatform-xapi-1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/mybatis/mybatis/3.2.2/mybatis-3.2.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/mybatis/mybatis-spring/1.2.0/mybatis-spring-1.2.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/tomcat/tomcat-dbcp/7.0.53/tomcat-dbcp-7.0.53.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-dbcp/commons-dbcp/1.4/commons-dbcp-1.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-pool/commons-pool/1.5.4/commons-pool-1.5.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/mysql/mysql-connector-java/5.1.31/mysql-connector-java-5.1.31.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/oracle/ojdbc14/10.2.0.4.0/ojdbc14-10.2.0.4.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/oracle/ojdbc6/11.2.0.3/ojdbc6-11.2.0.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjrt/1.7.3/aspectjrt-1.7.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjweaver/1.7.3/aspectjweaver-1.7.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/aspectj/aspectjtools/1.7.3/aspectjtools-1.7.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/servlet/servlet-api/2.5/servlet-api-2.5.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/servlet/jsp/jsp-api/2.1/jsp-api-2.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/servlet/jstl/1.2/jstl-1.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/annotation/jsr250-api/1.0/jsr250-api-1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-log4j12/1.6.6/slf4j-log4j12-1.6.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/log4j/log4j/1.2.15/log4j-1.2.15.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/lazyluke/log4jdbc-remix/0.2.7/log4jdbc-remix-0.2.7.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/jackson/jackson-mapper-asl/1.9.13/jackson-mapper-asl-1.9.13.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/jackson/jackson-core-asl/1.9.13/jackson-core-asl-1.9.13.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.6.4/jackson-core-2.6.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-databind/2.6.4/jackson-databind-2.6.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-annotations/2.6.0/jackson-annotations-2.6.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-io/commons-io/2.11.0/commons-io-2.11.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-codec/commons-codec/1.10/commons-codec-1.10.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/egovframework/rte/egovframework.rte.fdl.property/2.7.0/egovframework.rte.fdl.property-2.7.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/egovframework/rte/egovframework.rte.fdl.cmmn/2.7.0/egovframework.rte.fdl.cmmn-2.7.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-orm/3.0.5.RELEASE/spring-orm-3.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-test/3.0.5.RELEASE/spring-test-3.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/egovframework/rte/egovframework.rte.ptl.mvc/3.5.0/egovframework.rte.ptl.mvc-3.5.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/springmodules/spring-modules-validation/0.9/spring-modules-validation-0.9.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-validator/commons-validator/1.4.0/commons-validator-1.4.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-beanutils/commons-beanutils/1.8.3/commons-beanutils-1.8.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-digester/commons-digester/1.8/commons-digester-1.8.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/json/json/20250517/json-20250517.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/javax/inject/javax.inject/1/javax.inject-1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/plugins/maven-war-plugin/2.3/maven-war-plugin-2.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-plugin-api/2.0.6/maven-plugin-api-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-artifact/2.0.6/maven-artifact-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-model/2.0.6/maven-model-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-project/2.0.6/maven-project-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-profile/2.0.6/maven-profile-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-artifact-manager/2.0.6/maven-artifact-manager-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-plugin-registry/2.0.6/maven-plugin-registry-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-core/2.0.6/maven-core-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-file/1.0-beta-2/wagon-file-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-plugin-parameter-documenter/2.0.6/maven-plugin-parameter-documenter-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-http-lightweight/1.0-beta-2/wagon-http-lightweight-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-http-shared/1.0-beta-2/wagon-http-shared-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/jtidy/jtidy/4aug2000r7-dev/jtidy-4aug2000r7-dev.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/xml-apis/xml-apis/1.0.b2/xml-apis-1.0.b2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/reporting/maven-reporting-api/2.0.6/maven-reporting-api-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/doxia/doxia-sink-api/1.0-alpha-7/doxia-sink-api-1.0-alpha-7.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-repository-metadata/2.0.6/maven-repository-metadata-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-error-diagnostics/2.0.6/maven-error-diagnostics-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/commons-cli/commons-cli/1.0/commons-cli-1.0.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-ssh-external/1.0-beta-2/wagon-ssh-external-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-ssh-common/1.0-beta-2/wagon-ssh-common-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-plugin-descriptor/2.0.6/maven-plugin-descriptor-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/plexus/plexus-interactivity-api/1.0-alpha-4/plexus-interactivity-api-1.0-alpha-4.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/wagon/wagon-ssh/1.0-beta-2/wagon-ssh-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/jcraft/jsch/0.1.27/jsch-0.1.27.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/classworlds/classworlds/1.1/classworlds-1.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-settings/2.0.6/maven-settings-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-monitor/2.0.6/maven-monitor-2.0.6.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/maven-archiver/2.5/maven-archiver-2.5.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/plexus/plexus-io/2.0.5/plexus-io-2.0.5.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/plexus/plexus-archiver/2.2/plexus-archiver-2.2.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/plexus/plexus-interpolation/1.15/plexus-interpolation-1.15.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/plexus/plexus-container-default/1.0-alpha-9-stable-1/plexus-container-default-1.0-alpha-9-stable-1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/com/thoughtworks/xstream/xstream/1.4.3/xstream-1.4.3.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/xmlpull/xmlpull/1.1.3.1/xmlpull-1.1.3.1.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/xpp3/xpp3_min/1.1.4c/xpp3_min-1.1.4c.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/plexus/plexus-utils/3.0.8/plexus-utils-3.0.8.jar" enabled="true" runInBatchMode="false"/>
|
||||
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/maven/shared/maven-filtering/1.0-beta-2/maven-filtering-1.0-beta-2.jar" enabled="true" runInBatchMode="false"/>
|
||||
</factorypath>
|
||||
@@ -0,0 +1 @@
|
||||
/target/
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>RestBoard</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.springframework.ide.eclipse.core.springbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/org.eclipse.wst.jsdt.core.javascriptValidator (1).launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.zeroturnaround.eclipse.rebelXmlBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.springframework.ide.eclipse.core.springnature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
<nature>org.zeroturnaround.eclipse.jrebelNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
@@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.apt.aptEnabled=true
|
||||
org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
|
||||
org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations
|
||||
@@ -0,0 +1,17 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
|
||||
org.eclipse.jdt.core.compiler.processAnnotations=enabled
|
||||
org.eclipse.jdt.core.compiler.release=disabled
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<wb-module deploy-name="RestBoard">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/target/generated-sources/annotations"/>
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/target/generated-test-sources/test-annotations"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<property name="java-output-path" value="target/classes"/>
|
||||
|
||||
<property name="context-root" value="RestBoard"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</wb-module>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</project-modules>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faceted-project>
|
||||
<fixed facet="jst.web"/>
|
||||
<fixed facet="jst.java"/>
|
||||
<installed facet="jst.web" version="2.5"/>
|
||||
<installed facet="jst.java" version="1.8"/>
|
||||
</faceted-project>
|
||||
@@ -0,0 +1,6 @@
|
||||
DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator\=org.eclipse.wst.wsdl.validation.internal.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator;
|
||||
USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.jst.jsf.validation.internal.JSPSemanticsValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.common.componentcore.internal.ModuleCoreValidator;org.eclipse.jst.jsf.validation.internal.appconfig.AppConfigValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPContentValidator;org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;
|
||||
USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.jst.jsf.validation.internal.JSPSemanticsValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.common.componentcore.internal.ModuleCoreValidator;org.eclipse.jst.jsf.validation.internal.appconfig.AppConfigValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPContentValidator;org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;
|
||||
USER_PREFERENCE=overrideGlobalPreferencesfalse
|
||||
disabled=06target
|
||||
eclipse.preferences.version=1
|
||||
@@ -0,0 +1,78 @@
|
||||
#Mon Oct 18 12:37:52 EDT 2010
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.osgi.org/xmlns/blueprint/v1.0.0=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/aop=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/batch=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/beans=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/context=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/faces=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/flex=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/file=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/http=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/httpinvoker=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/ip=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/jdbc=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/jms=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/jmx=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/mail=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/rmi=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/security=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/stream=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/ws=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/integration/xml=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/jdbc=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/jee=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/jms=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/lang=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/mvc=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/osgi=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/osgi-compendium=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/oxm=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/p=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/security=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/task=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/tx=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/util=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/web-services=
|
||||
//org.springframework.ide.eclipse.beans.core.default.version.http\://www.springframework.org/schema/webflow-config=
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.osgi.org/xmlns/blueprint/v1.0.0=bp
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/aop=aop
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/batch=batch
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/beans=beans
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/context=context
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/faces=faces
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/flex=flex
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration=int
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/file=int-file
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/http=int-http
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/httpinvoker=int-httpinvoker
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/ip=int-ip
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/jdbc=int-jdbc
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/jms=int-jms
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/jmx=int-jmx
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/mail=int-mail
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/rmi=int-rmi
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/security=int-security
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/stream=int-stream
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/ws=int-ws
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/integration/xml=int-xml
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/jdbc=jdbc
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/jee=jee
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/jms=jms
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/lang=lang
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/mvc=mvc
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/osgi=osgi
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/osgi-compendium=osgix
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/oxm=oxm
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/p=p
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/security=sec
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/task=task
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/tx=tx
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/util=util
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/web-services=ws
|
||||
//org.springframework.ide.eclipse.beans.core.prefix.http\://www.springframework.org/schema/webflow-config=flow
|
||||
eclipse.preferences.version=1
|
||||
org.springframework.ide.eclipse.beans.core.default.version.check.classpath=true
|
||||
org.springframework.ide.eclipse.beans.core.enable.project.preferences=false
|
||||
org.springframework.ide.eclipse.beans.core.ignoreMissingNamespaceHandler=false
|
||||
org.springframework.ide.eclipse.beans.core.loadNamespaceHandlerFromClasspath=false
|
||||
@@ -0,0 +1,69 @@
|
||||
#Tue Apr 20 16:59:06 EDT 2010
|
||||
eclipse.preferences.version=1
|
||||
org.springframework.ide.eclipse.core.builders.enable.aopreferencemodelbuilder=true
|
||||
org.springframework.ide.eclipse.core.builders.enable.beanmetadatabuilder=true
|
||||
org.springframework.ide.eclipse.core.builders.enable.osgibundleupdater=false
|
||||
org.springframework.ide.eclipse.core.enable.project.preferences=false
|
||||
org.springframework.ide.eclipse.core.validator.enable.com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.core.springvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivationPolicyRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivatorRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleManifestVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.exportPackageRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.importRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.parsingProblemsRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.requireBundleRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.AvoidDriverManagerDataSource-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ImportElementsAtTopRulee-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ParentBeanSpecifiesAbstractClassRule-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.RefElementRule-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.TooManyBeansInFileRule-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UnnecessaryValueElementRule-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UseBeanInheritance-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.legacyxmlusage.jndiobjectfactory-com.springsource.sts.bestpractices.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importLibraryVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importPackageVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.requireBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.autowire.autowire-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinition-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinitionHolder-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanFactory-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanInitDestroyMethod-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanReference-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.requiredProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.toolAnnotation-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.core.springClasspath-org.springframework.ide.eclipse.core.springvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.action-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.actionstate-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attribute-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attributemapper-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.beanaction-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationaction-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationresult-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.exceptionhandler-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.import-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.inputattribute-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.mapping-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.outputattribute-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.set-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.state-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.subflowstate-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.transition-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.variable-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.webflowstate-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[3.6.4.201503051146-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[true]]></enableImports>
|
||||
<configs>
|
||||
</configs>
|
||||
<autoconfigs>
|
||||
</autoconfigs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
</beansProjectDescription>
|
||||
@@ -0,0 +1,805 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.company</groupId>
|
||||
|
||||
<artifactId>RestBoard</artifactId>
|
||||
|
||||
<name>RestBoard</name>
|
||||
|
||||
<packaging>war</packaging>
|
||||
|
||||
<version>1.0.0-BUILD-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
|
||||
<java-version>1.8</java-version>
|
||||
|
||||
<org.springframework-version>4.3.25.RELEASE</org.springframework-version>
|
||||
|
||||
<org.aspectj-version>1.7.3</org.aspectj-version>
|
||||
|
||||
<org.slf4j-version>1.6.6</org.slf4j-version>
|
||||
|
||||
</properties>
|
||||
|
||||
|
||||
<repositories>
|
||||
|
||||
<repository>
|
||||
|
||||
<id>mvn2</id>
|
||||
|
||||
<url>http://repo1.maven.org/maven2/</url>
|
||||
|
||||
<releases>
|
||||
|
||||
<enabled>true</enabled>
|
||||
|
||||
</releases>
|
||||
|
||||
<snapshots>
|
||||
|
||||
<enabled>true</enabled>
|
||||
|
||||
</snapshots>
|
||||
|
||||
</repository>
|
||||
|
||||
|
||||
<repository>
|
||||
|
||||
<id>egovframe</id>
|
||||
|
||||
<url>https://maven.egovframe.go.kr/maven</url>
|
||||
|
||||
<releases>
|
||||
|
||||
<enabled>true</enabled>
|
||||
|
||||
</releases>
|
||||
|
||||
<snapshots>
|
||||
|
||||
<enabled>false</enabled>
|
||||
|
||||
</snapshots>
|
||||
|
||||
</repository>
|
||||
|
||||
|
||||
<!-- <repository>
|
||||
|
||||
<id>oracle</id>
|
||||
|
||||
<name>ORACLE JDBC Repository</name>
|
||||
|
||||
<url>http://mesir.googlecode.com/svn/trunk/mavenrepo</url>
|
||||
|
||||
</repository>
|
||||
|
||||
-->
|
||||
|
||||
<!-- 2016.01.08 -->
|
||||
|
||||
<repository>
|
||||
|
||||
<id>codelds</id>
|
||||
|
||||
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
|
||||
|
||||
</repository>
|
||||
|
||||
|
||||
|
||||
|
||||
</repositories>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--lombok -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
||||
<artifactId>lombok</artifactId>
|
||||
|
||||
<version>1.18.32</version>
|
||||
|
||||
<scope>provided</scope>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Spring -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-context</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
<exclusions>
|
||||
|
||||
<!-- Exclude Commons Logging in favor of SLF4j -->
|
||||
|
||||
<exclusion>
|
||||
|
||||
<groupId>commons-logging</groupId>
|
||||
|
||||
<artifactId>commons-logging</artifactId>
|
||||
|
||||
</exclusion>
|
||||
|
||||
</exclusions>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-web</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-aop</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-beans</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-core</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.springframework</groupId>
|
||||
|
||||
<artifactId>spring-tx</artifactId>
|
||||
|
||||
<version>${org.springframework-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Tobesoft Repo -->
|
||||
<dependency>
|
||||
<groupId>com.nexacro</groupId>
|
||||
<artifactId>nexacro17-xapi</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nexacro</groupId>
|
||||
<artifactId>nexacro-xapi</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tobesoft</groupId>
|
||||
<artifactId>xplatform-xapi</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- AOP Alliance -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>aopalliance</groupId>
|
||||
|
||||
<artifactId>aopalliance</artifactId>
|
||||
|
||||
<version>1.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- MyBatis -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.mybatis</groupId>
|
||||
|
||||
<artifactId>mybatis</artifactId>
|
||||
|
||||
<version>3.2.2</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.mybatis</groupId>
|
||||
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
|
||||
<version>1.2.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- DBCP -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
|
||||
<artifactId>tomcat-dbcp</artifactId>
|
||||
|
||||
<scope>provided</scope>
|
||||
|
||||
<version>7.0.53</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>commons-dbcp</groupId>
|
||||
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
|
||||
<version>1.4</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- MySql -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>mysql</groupId>
|
||||
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
|
||||
<version>5.1.31</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Oracle -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>com.oracle</groupId>
|
||||
|
||||
<artifactId>ojdbc14</artifactId>
|
||||
|
||||
<version>10.2.0.4.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 2016.01.08 -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>com.oracle</groupId>
|
||||
|
||||
<artifactId>ojdbc6</artifactId>
|
||||
|
||||
<version>11.2.0.3</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- AspectJ -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.aspectj</groupId>
|
||||
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
|
||||
<version>${org.aspectj-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.aspectj</groupId>
|
||||
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
|
||||
<version>${org.aspectj-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.aspectj</groupId>
|
||||
|
||||
<artifactId>aspectjtools</artifactId>
|
||||
|
||||
<version>${org.aspectj-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Web -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>javax.servlet</groupId>
|
||||
|
||||
<artifactId>servlet-api</artifactId>
|
||||
|
||||
<scope>provided</scope>
|
||||
|
||||
<version>2.5</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
|
||||
<artifactId>jsp-api</artifactId>
|
||||
|
||||
<scope>provided</scope>
|
||||
|
||||
<version>2.1</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>javax.servlet</groupId>
|
||||
|
||||
<artifactId>jstl</artifactId>
|
||||
|
||||
<version>1.2</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>javax.annotation</groupId>
|
||||
|
||||
<artifactId>jsr250-api</artifactId>
|
||||
|
||||
<version>1.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Logging -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
|
||||
<version>${org.slf4j-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
|
||||
<version>${org.slf4j-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
|
||||
<version>${org.slf4j-version}</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>log4j</groupId>
|
||||
|
||||
<artifactId>log4j</artifactId>
|
||||
|
||||
<version>1.3alpha-8</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.lazyluke</groupId>
|
||||
|
||||
<artifactId>log4jdbc-remix</artifactId>
|
||||
|
||||
<version>0.2.7</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- MappingJacksonJsonView -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
|
||||
<version>1.9.13</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
|
||||
<version>1.9.13</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
||||
<artifactId>jackson-core</artifactId>
|
||||
|
||||
<version>2.6.4</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
|
||||
<version>2.6.4</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- MultipartHttpServletRequset -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>commons-io</groupId>
|
||||
|
||||
<artifactId>commons-io</artifactId>
|
||||
|
||||
<version>2.11.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>commons-fileupload</groupId>
|
||||
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
|
||||
<version>1.4</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Apache Codec -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>commons-codec</groupId>
|
||||
|
||||
<artifactId>commons-codec</artifactId>
|
||||
|
||||
<version>1.10</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- EgovProperty -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>egovframework.rte</groupId>
|
||||
|
||||
<artifactId>egovframework.rte.fdl.property</artifactId>
|
||||
|
||||
<version>2.7.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency> <!-- 페이징처리 위해 추가 -->
|
||||
|
||||
<groupId>egovframework.rte</groupId>
|
||||
|
||||
<artifactId>egovframework.rte.ptl.mvc</artifactId>
|
||||
|
||||
<version>3.5.0</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.json/json -->
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20250517</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Log4j -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>log4j</groupId>
|
||||
|
||||
<artifactId>log4j</artifactId>
|
||||
|
||||
<version>1.2.15</version>
|
||||
|
||||
<exclusions>
|
||||
|
||||
<exclusion>
|
||||
|
||||
<groupId>javax.mail</groupId>
|
||||
|
||||
<artifactId>mail</artifactId>
|
||||
|
||||
</exclusion>
|
||||
|
||||
<exclusion>
|
||||
|
||||
<groupId>javax.jms</groupId>
|
||||
|
||||
<artifactId>jms</artifactId>
|
||||
|
||||
</exclusion>
|
||||
|
||||
<exclusion>
|
||||
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
|
||||
<artifactId>jmxtools</artifactId>
|
||||
|
||||
</exclusion>
|
||||
|
||||
<exclusion>
|
||||
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
|
||||
<artifactId>jmxri</artifactId>
|
||||
|
||||
</exclusion>
|
||||
|
||||
</exclusions>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- @Inject -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>javax.inject</groupId>
|
||||
|
||||
<artifactId>javax.inject</artifactId>
|
||||
|
||||
<version>1</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
|
||||
<version>2.3</version>
|
||||
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Test -->
|
||||
|
||||
<dependency>
|
||||
|
||||
<groupId>junit</groupId>
|
||||
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
<version>4.7</version>
|
||||
|
||||
<scope>test</scope>
|
||||
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
<build>
|
||||
|
||||
<defaultGoal>install</defaultGoal>
|
||||
|
||||
<directory>${basedir}/target</directory>
|
||||
|
||||
<finalName>RestBoard</finalName>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
|
||||
<version>2.9</version>
|
||||
|
||||
<configuration>
|
||||
|
||||
<additionalProjectnatures>
|
||||
|
||||
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
|
||||
|
||||
</additionalProjectnatures>
|
||||
|
||||
<additionalBuildcommands>
|
||||
|
||||
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
|
||||
|
||||
</additionalBuildcommands>
|
||||
|
||||
<downloadSources>true</downloadSources>
|
||||
|
||||
<downloadJavadocs>true</downloadJavadocs>
|
||||
|
||||
</configuration>
|
||||
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
|
||||
<version>2.5.1</version>
|
||||
|
||||
<configuration>
|
||||
|
||||
<source>${java-version}</source>
|
||||
|
||||
<target>${java-version}</target>
|
||||
|
||||
<encoding>UTF-8</encoding>
|
||||
|
||||
<compilerArgument>-Xlint:all</compilerArgument>
|
||||
|
||||
<showWarnings>true</showWarnings>
|
||||
|
||||
<showDeprecation>true</showDeprecation>
|
||||
|
||||
</configuration>
|
||||
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
|
||||
<version>1.2.1</version>
|
||||
|
||||
<configuration>
|
||||
|
||||
<mainClass>org.test.int1.Main</mainClass>
|
||||
|
||||
</configuration>
|
||||
|
||||
</plugin>
|
||||
|
||||
|
||||
<!-- JavaDoc -->
|
||||
|
||||
<plugin>
|
||||
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
|
||||
<version>2.5</version>
|
||||
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
|
||||
<version>3.2.2</version>
|
||||
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,85 @@
|
||||
# React 게시판 프로젝트 개발 가이드 (실무 실습용)
|
||||
|
||||
이 가이드는 `react_board` 프로젝트의 스켈레톤 코드를 완성해 나가는 과정에서 필요한 기술 스펙과 구현 팁을 담고 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 프로젝트 환경
|
||||
- **Framework**: React 19 (Vite 기반)
|
||||
- **Language**: TypeScript
|
||||
- **Styling**: Bootstrap (CDN 방식)
|
||||
- **API Client**: Axios
|
||||
- **Routing**: React Router DOM (v7)
|
||||
|
||||
---
|
||||
|
||||
## 2. API 명세서 (Backend Specification)
|
||||
백엔드 서버 주소는 `.env` 파일의 `VITE_API_BASE_URL`을 사용합니다. (기본값: `http://localhost:8080/RestBoard`)
|
||||
|
||||
### 📋 게시글 목록 조회
|
||||
- **Method**: `GET`
|
||||
- **Path**: `/board/api/list`
|
||||
- **Query Params**:
|
||||
- `type`: 검색 타입 (`title`, `content`, `creaNm`)
|
||||
- `keyword`: 검색어
|
||||
- `page`: 페이지 번호 (1부터 시작)
|
||||
- **Response Structure**:
|
||||
```json
|
||||
{
|
||||
"list": [ { "idx": 1, "title": "제목", ... }, ... ],
|
||||
"totalpage": 10
|
||||
}
|
||||
```
|
||||
|
||||
### 📋 게시글 상세 조회
|
||||
- **Method**: `GET`
|
||||
- **Path**: `/board/api/detail/{id}`
|
||||
- **Response Structure**:
|
||||
```json
|
||||
{ "detail": { "idx": 1, "title": "제목", "contents": "내용", ... } }
|
||||
```
|
||||
|
||||
### 📋 게시글 등록
|
||||
- **Method**: `POST`
|
||||
- **Path**: `/board/api/write`
|
||||
- **Request Body**: `{ "title": "string", "creaNm": "string", "contents": "string" }`
|
||||
|
||||
---
|
||||
|
||||
## 3. 데이터 타입 (Data Types)
|
||||
`src/types/board.ts`에 정의된 인터페이스를 적극 활용하세요.
|
||||
|
||||
- **IBoardItem**: 게시글 하나의 정보를 담는 객체.
|
||||
- **IBoardResponse**: 목록 조회 시 서버로부터 받는 전체 데이터 구조.
|
||||
- **IBoardDetailResponse**: 상세 조회 시의 데이터 구조.
|
||||
|
||||
---
|
||||
|
||||
## 4. 컴포넌트별 구현 가이드
|
||||
|
||||
### 📍 [BoardList.tsx](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/react_board/src/components/BoardList.tsx)
|
||||
- **핵심 로직**: `currentPage`와 `submittedSearchTerm`이 변경될 때마다 `retriveBoard()` 함수를 호출하도록 `useEffect`를 구성하세요.
|
||||
- **팁**: 검색 버튼을 눌렀을 때만 검색이 실행되도록 하려면, 입력 중인 상태(`searchTerm`)와 실제 검색에 사용될 상태(`submittedSearchTerm`)를 분리하는 것이 좋습니다.
|
||||
|
||||
### 📍 [Pagination.tsx](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/react_board/src/components/Pagination.tsx)
|
||||
- **핵심 로직**: 한 그룹에 10페이지씩 보여준다면, 현재 페이지(`currentPage`)를 기준으로 그룹의 `startPage`를 계산하세요.
|
||||
- **계산식**: `startPage = Math.floor((currentPage - 1) / 10) * 10 + 1`
|
||||
- **팁**: `endPage`는 `startPage + 9`와 `totalPages` 중 더 작은 값을 택해야 에러가 나지 않습니다.
|
||||
|
||||
### 📍 [PostView.tsx](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/react_board/src/components/PostView.tsx)
|
||||
- **핵심 로직**: `useParams()`로 전달받은 `id` 값을 `useEffect`의 의존성 배열에 넣어 ID가 바뀔 때마다 데이터를 새로 불러옵니다.
|
||||
- **UX**: 로딩 중일 때 사용자에게 피드백을 주기 위해 `loading` 상태 변수를 `boolean`으로 관리하세요.
|
||||
|
||||
### 📍 [PostForm.tsx](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/react_board/src/components/PostForm.tsx)
|
||||
- **핵심 로직**: React의 **제어 컴포넌트(Controlled Components)** 패턴을 사용하여 폼 데이터를 관리하세요.
|
||||
- **주의사항**: `axios.post` 시 데이터 전송이 성공(`try`)하면 반드시 목록으로 이동(`useNavigate`)하게 하여 이중 등록되지 않도록 하세요.
|
||||
|
||||
---
|
||||
|
||||
## 5. 학습 포인트
|
||||
> [!IMPORTANT]
|
||||
> - **불변성(Immutability)**: React 상태를 업데이트할 때는 기존 배열이나 객체를 직접 수정하지 말고, 구조 분해 할당(`[...]`)이나 복사본을 만들어 새 값을 설정하세요.
|
||||
> - **의존성 배열(Dependency Array)**: `useEffect`의 두 번째 인자인 배열을 잘못 설정하면 무한 루프에 빠지거나 데이터가 갱신되지 않을 수 있습니다. 항상 "어떤 값이 변할 때 이 함수를 불러야 하는가"를 고민하세요.
|
||||
|
||||
---
|
||||
가이드 문서의 내용이 이해되지 않거나 더 구체적인 코드가 필요하시면 언제든 **AI 튜터**에게 물어보세요!
|
||||
@@ -0,0 +1,55 @@
|
||||
# 프론트엔드 실습용 백엔드 연동 힌트 및 첨부 파일 이슈 분석
|
||||
|
||||
이 문서는 `BoardRestController` 분석을 통해 도출된 프론트엔드 구현 힌트와, 현재 시스템 구조에서 첨부 파일 기능을 추가할 때 발생하는 기술적 병목 지점을 정리한 리포트입니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 프론트엔드 구현을 위한 API 매핑 힌트
|
||||
프론트엔드 스켈레톤 코드의 `TODO:` 부분을 채울 때 다음 매핑 테이블을 참고하세요.
|
||||
|
||||
| 기능 | API 경로 (Endpoint) | HTTP 메서드 | 프론트엔드 전달 데이터 | 주의사항 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **목록 조회** | `/board/api/list` | `GET` | Query Params: `page`, `type`, `keyword` | `res.data.list`와 `res.data.totalpage` 바인딩 |
|
||||
| **상세 조회** | `/board/api/detail/{idx}` | `GET` | Path Variable: `idx` | 조회수 자동 증가 로직 포함됨 |
|
||||
| **게시물 등록** | `/board/api/detail` | **`POST`** | **JSON Body**: `{ title, creaNm, contents }` | **주의**: URL이 `/write`가 아닌 `/detail`임 |
|
||||
| **게시물 수정** | `/board/api/detail/{idx}` | `POST` | JSON Body + Path Variable | 수정 성공 시 `code: "0"` 반환 |
|
||||
| **게시물 삭제** | `/board/api/detail/{idx}` | `DELETE` | Path Variable: `idx` | Soft Delete (DEL_GB='Y') 방식 |
|
||||
|
||||
> [!TIP]
|
||||
> 백엔드 응답에서 게시글 번호는 소문자 `idx`로 내려옵니다. (DB 컬럼명은 대문자이나 `BoardRestController`에서 소문자로 맵핑함)
|
||||
|
||||
---
|
||||
|
||||
## 2. 첨부 파일 기능 구현의 구조적 문제 분석
|
||||
|
||||
현재 프로젝트 구조에서 첨부 파일 기능을 구현하려고 하면 다음과 같은 **"기술적 장벽"**에 부딪히게 됩니다.
|
||||
|
||||
### 🚫 문제 1: Media Type 충돌 (JSON vs Multipart)
|
||||
- **현상**: `BoardRestController`의 등록/수정 메서드는 `consumes = {MediaType.APPLICATION_JSON_VALUE}`로 선언되어 있습니다.
|
||||
- **원인**: 이 설정은 **오직 JSON 데이터만** 받겠다는 뜻입니다. 파일 업로드에 필수적인 `multipart/form-data` 형식의 요청을 보내면 `415 Unsupported Media Type` 에러가 발생합니다.
|
||||
- **해결**: `consumes` 설정을 제거하거나 `MULTIPART_FORM_DATA_VALUE`를 지원하도록 확장해야 합니다.
|
||||
|
||||
### 🚫 문제 2: 컨트롤러 파라미터 설계 미흡
|
||||
- **현상**: `FileUtils.java`에서 파일을 추출하려면 `HttpServletRequest` 객체가 필요합니다.
|
||||
- **원인**: 현재 `BoardRestController`의 메서드들은 `HttpServletRequest`를 인자로 받고 있지 않고, 오직 `@RequestBody Map`만 받고 있습니다. 파일 데이터가 담긴 요청 객체에 접근할 방법이 없습니다.
|
||||
|
||||
### 🚫 문제 3: 서비스 계층의 로직 부재 (Business Logic Gap)
|
||||
- **현상**: 게시글 저장 기능인 `insertBoardDetail` 메서드 내부에 파일 저장 호출 코드가 없습니다.
|
||||
- **원인**: 단순히 `boardDAO.insertBoardDetail`만 호출하고 끝납니다. 원래는 `FileUtils.parseInsertFileInfo`를 호출하여 리턴된 파일 리스트를 다시 `boardDAO.insertFile`과 같은 메서드로 전달하는 로직이 추가되어야 합니다.
|
||||
|
||||
### 🚫 문제 4: MyBatis 매퍼 및 DB 테이블 정의 부족
|
||||
- **현상**: `Board_SQL.xml`에 게시글과 연관된 파일 정보를 저장하거나 조회하는 쿼리가 없습니다.
|
||||
- **원인**: 파일 정보를 저장할 `TB_FILE`과 같은 테이블 정의와 이를 처리할 전용 SQL문이 누락되어 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 해결 방안 제언 (Refactoring Path)
|
||||
|
||||
첨부 파일 기능을 학습 목적으로 구현하고 싶다면 다음 순서로 코드를 수정해 보세요.
|
||||
|
||||
1. **Backend (Controller)**: `consumes` 설정을 풀고, 인자에 `MultipartHttpServletRequest`를 추가합니다.
|
||||
2. **Backend (Service)**: 게시물 저장 후 리턴된 `idx`를 사용하여 `fileUtils.parseInsertFileInfo`를 호출하고, 그 결과를 파일 전용 테이블에 저장하는 SQL을 호출합니다.
|
||||
3. **Frontend**: `axios` 요청 시 데이터를 객체(`{}`)가 아닌 **`new FormData()`** 객체로 감싸서 보내야 합니다.
|
||||
|
||||
---
|
||||
현재 구조는 **"기본 CRUD 실습"**에는 매우 최적화되어 있으나, **"파일 업로드"**는 별도의 심화 단계로 다루는 것이 적절해 보입니다.
|
||||
@@ -0,0 +1,64 @@
|
||||
# Vue 게시판 프로젝트 개발 가이드 (실무 실습용)
|
||||
|
||||
이 가이드는 `vue_board` 프로젝트의 스켈레톤 코드를 완성해 나가는 과정에서 필요한 기술 스펙과 Vue 고유의 구현 전략을 담고 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 프로젝트 환경
|
||||
- **Framework**: Vue 3 (Options API 방식)
|
||||
- **Language**: TypeScript
|
||||
- **Styling**: W3.CSS (CDN 방식)
|
||||
- **API Client**: Axios (Global Plug-in 등록)
|
||||
- **Routing**: Vue Router (v4)
|
||||
|
||||
---
|
||||
|
||||
## 2. API 명세서 (Backend Specification)
|
||||
백엔드 주소는 전역 변수인 `this.$serverUrl`을 사용하여 접근합니다.
|
||||
|
||||
### 📋 API 엔드포인트 목록
|
||||
- **목록 조회**: `GET /board/api/list` (params: type, keyword, page)
|
||||
- **상세 조회**: `GET /board/api/detail/{idx}`
|
||||
- **글 등록**: `POST /board/api/write` (body: JSON)
|
||||
- **글 삭제**: `DELETE /board/api/delete/{idx}`
|
||||
|
||||
---
|
||||
|
||||
## 3. 전역 속성 활용 (this.$...)
|
||||
`main.ts`에 등록된 다음 속성들을 사용하여 코드를 간결하게 작성하세요.
|
||||
|
||||
- **`this.$axios`**: Axios 별칭. 별도의 import 없이 `this.$axios.get(...)` 형태로 사용합니다.
|
||||
- **`this.$serverUrl`**: 백엔드 API 서버의 기본 경로입니다.
|
||||
- **`this.$router`**: 페이지 이동 제어 (예: `this.$router.push(...)`).
|
||||
- **`this.$route`**: 현재 라우트 정보 접근 (예: `this.$route.params.idx`).
|
||||
|
||||
---
|
||||
|
||||
## 4. 컴포넌트별 구현 가이드
|
||||
|
||||
### 📍 [BoardList.vue](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/vue_board/src/views/BoardList.vue)
|
||||
- **핵심 로직**: `v-for` 디렉티브를 사용하여 `boardItems` 배열을 반복 렌더링하세요.
|
||||
- **팁**: 검색 버튼 클릭 시 `currentPage`를 1로 초기화하고 데이터를 다시 불러오도록 `handleSearch` 메서드를 작성하세요.
|
||||
|
||||
### 📍 [Pagination.vue](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/vue_board/src/components/Pagination.vue)
|
||||
- **핵심 로직**: `props`로 받은 `currentPage`와 `totalPages`를 기반으로 페이지 번호를 생성하세요.
|
||||
- **통신**: 페이지 번호 클릭 시 `this.$emit('page-change', pageNumber)`를 통해 부모(BoardList)에게 알리세요.
|
||||
- **팁**: 반복되는 페이지 번호 배열은 `computed` 속성을 사용하여 가공하는 것이 성능상 유리합니다.
|
||||
|
||||
### 📍 [BoardDetail.vue](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/vue_board/src/views/BoardDetail.vue)
|
||||
- **핵심 로직**: `this.$route.params.idx`를 통해 URL의 ID 값을 가져와 `mounted()` 시점에 상세 조회를 실행합니다.
|
||||
- **삭제**: `this.$axios.delete()`를 호출한 뒤 성공 시 목록으로 이동하도록 구현하세요.
|
||||
|
||||
### 📍 [BoardWrite.vue](file:///c:/DEV/spring-workspace/RestBoard/src/main/front_end/vue_board/src/views/BoardWrite.vue)
|
||||
- **핵심 로직**: `v-model` 디렉티브를 사용하여 `input`과 `textarea`의 값을 `data()` 객체와 실시간으로 동기화하세요.
|
||||
- **팁**: 작성 완료 후 `this.$router.push({ name: 'board' })`를 사용하여 목록으로 돌아갑니다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 학습 포인트
|
||||
> [!IMPORTANT]
|
||||
> - **Reactivity**: `data()` 함수에서 반환하는 객체의 속성들은 Vue가 자동으로 변화를 감지하여 화면을 업데이트합니다.
|
||||
> - **Directives**: `v-if`(조건부), `v-for`(반복), `v-on`(@ 기호로 대체), `v-bind`(: 기호로 대체) 등 전용 문법의 사용법에 익숙해지세요.
|
||||
|
||||
---
|
||||
Vue의 선언적인 문법과 강력한 데이터 바인딩 기능을 활용해 멋진 게시판을 완성해 보세요!
|
||||
@@ -0,0 +1 @@
|
||||
VITE_API_BASE_URL=http://localhost:8080/RestBoard
|
||||
@@ -0,0 +1 @@
|
||||
/node_modules/
|
||||
@@ -0,0 +1,12 @@
|
||||
# React + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
@@ -0,0 +1,29 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||
},
|
||||
},
|
||||
])
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "react_board",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.12.2",
|
||||
"bootstrap": "^5.3.8",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router-dom": "^7.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/react": "^19.1.13",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@vitejs/plugin-react": "^5.0.2",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.4.0",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^7.1.6"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import Header from './components/Header';
|
||||
import BoardList from './components/BoardList';
|
||||
import PostView from './components/PostView';
|
||||
import PostForm from './components/PostForm';
|
||||
import PostEditForm from './components/PostEditForm';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Header />
|
||||
<div className="container mt-4">
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="/" element={<BoardList />} />
|
||||
<Route path="/post/:id" element={<PostView />} />
|
||||
<Route path="/new" element={<PostForm />} />
|
||||
<Route path="/edit/:id" element={<PostEditForm/>}/>
|
||||
</Routes>
|
||||
</main>
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,31 @@
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.pagination button {
|
||||
margin: 0 5px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.pagination button:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.pagination button:disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pagination button.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import axios from "axios";
|
||||
import { IBoardDetailResponse, IBoardResponse } from "../types/board";
|
||||
|
||||
export const boardAPI = {
|
||||
retriveBoard: async (type: String, keyword: String, page: Number) => {
|
||||
const API_BASE_URL:String = import.meta.env.VITE_API_BASE_URL;
|
||||
const URL = `${API_BASE_URL}/board/api/list`
|
||||
const response = await axios.get<IBoardResponse>(URL, {
|
||||
params: {
|
||||
"type": type,
|
||||
"keyword": keyword,
|
||||
"page": page
|
||||
}
|
||||
}).then(response => {
|
||||
console.log("response : ", response);
|
||||
return response;
|
||||
});
|
||||
return response;
|
||||
},
|
||||
fetchPost: async(id: String)=>{
|
||||
const API_BASE_URL:string = import.meta.env.VITE_API_BASE_URL;
|
||||
const URL = `${API_BASE_URL}/board/api/detail/${id}`;
|
||||
const response = await axios.get<IBoardDetailResponse>(URL);
|
||||
return response;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,144 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import Pagination from './Pagination';
|
||||
import { IBoardItem, IBoardResponse } from '../types/board';
|
||||
import { boardAPI } from '../api/boards';
|
||||
|
||||
/**
|
||||
* [실습 Phase 1 & 5] 게시판 목록 및 검색 컴포넌트
|
||||
*
|
||||
* 가이드:
|
||||
* 1. useState를 사용하여 게시글 목록(posts), 검색어(searchTerm), 현재 페이지(currentPage), 전체 페이지(totalPages) 상태를 정의하세요.
|
||||
* 2. useEffect를 사용하여 컴포넌트 마운트 시와 페이지/검색어 변경 시 데이터를 가져오는 로직을 구현하세요.
|
||||
* 3. axios를 사용하여 `${import.meta.env.VITE_API_BASE_URL}/board/api/list`에 GET 요청을 보내세요.
|
||||
* - 파라미터: type (검색타입), keyword (검색어), page (현재페이지)
|
||||
* 4. 검색 버튼 클릭 및 엔터키 입력 시 검색이 실행되도록 핸들러를 작성하세요.
|
||||
*/
|
||||
const BoardList: React.FC = () => {
|
||||
// TODO: 실습에 필요한 상태(State)를 정의하세요.
|
||||
const [posts, setPosts] = useState<IBoardItem[]>([]);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [submittedSearchTerm, setSubmittedSearchTerm] = useState('');
|
||||
const [searchType, setSearchType] = useState('title');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
|
||||
// TODO: API 호출 함수(retriveBoard)를 작성하세요.
|
||||
const retriveBoard = async () => {
|
||||
const response = await boardAPI.retriveBoard(searchType, submittedSearchTerm, currentPage);
|
||||
// 조회된 게시글 목록 상태 업데이트
|
||||
setPosts(response.data.list);
|
||||
// 전체 페이지 개수 업데이트
|
||||
setTotalPages(response.data.totalpage);
|
||||
};
|
||||
|
||||
const handleSearch = async () => {
|
||||
const page = 1;
|
||||
const response = await boardAPI.retriveBoard(searchType, submittedSearchTerm, page);
|
||||
// 조회된 게시글 목록 상태 업데이트
|
||||
setPosts(response.data.list);
|
||||
// 전체 페이지 개수 업데이트
|
||||
setTotalPages(response.data.totalpage);
|
||||
// 현재 페이지를 첫번째 페이지로 업데이트
|
||||
setCurrentPage(1)
|
||||
console.log("response : ", response);
|
||||
};
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
// 페이지 변경 로직 구현
|
||||
setCurrentPage(page);
|
||||
};
|
||||
|
||||
// TODO: useEffect를 사용하여 데이터 로드 시점을 제어하세요.
|
||||
useEffect(() => {
|
||||
retriveBoard();
|
||||
}, [currentPage, submittedSearchTerm]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="mb-4">Board</h2>
|
||||
|
||||
{/* 검색 바 영역 */}
|
||||
<div className="row justify-content-between mb-3">
|
||||
<div className="col-md-auto">
|
||||
<Link to="/new" className="btn btn-primary">New Post</Link>
|
||||
</div>
|
||||
<div className="col-md-7">
|
||||
<div className="input-group">
|
||||
<select
|
||||
className="form-select"
|
||||
style={{ flex: '0 0 120px' }}
|
||||
value={searchType}
|
||||
onChange={(e) => setSearchType(e.target.value)}
|
||||
>
|
||||
<option value="title">Title</option>
|
||||
<option value="content">Content</option>
|
||||
<option value="creaId">CreaId</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Search..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/* TODO: 엔터키 입력 시 검색 실행 (onKeyDown) */
|
||||
onKeyDown={(e)=>{
|
||||
const key = e.key;
|
||||
if(key !== 'Enter'){
|
||||
return;
|
||||
}
|
||||
setSubmittedSearchTerm(searchTerm);
|
||||
}}
|
||||
/>
|
||||
<button className="btn btn-outline-secondary" type="button" onClick={handleSearch}>Search</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 목록 테이블 영역 */}
|
||||
<div className="table-responsive">
|
||||
<table className="table table-hover">
|
||||
<thead className="table-light">
|
||||
<tr>
|
||||
<th>No.</th>
|
||||
<th>Title</th>
|
||||
<th>CreaId</th>
|
||||
<th>Date</th>
|
||||
<th>Hits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{/* TODO: posts 배열을 순회하며 목록을 출력하세요. (.map 활용) */}
|
||||
{posts.length > 0 ? (
|
||||
posts.map((post) => (
|
||||
<tr key={post.idx}>
|
||||
<td>{post.rnum}</td>
|
||||
<td>
|
||||
<Link to={`/post/${post.idx}`}>{post.title}</Link>
|
||||
</td>
|
||||
<td>{post.creaId}</td>
|
||||
<td>{post.creaDtm}</td>
|
||||
<td>{post.hitCnt}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={5} className="text-center py-5">데이터가 없습니다. 로직을 구현해 보세요!</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* 페이징 컴포넌트 호출 */}
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPageChange={handlePageChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoardList;
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
return (
|
||||
<header>
|
||||
<nav className="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm">
|
||||
<div className="container">
|
||||
<Link className="navbar-brand fw-bold" to="/">React Board</Link>
|
||||
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div className="collapse navbar-collapse" id="navbarNav">
|
||||
<ul className="navbar-nav ms-auto">
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/">Home</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/new">New Post</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
|
||||
interface PaginationProps {
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
onPageChange: (page: number) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* [실습 Phase 2] 공통 페이징 컴포넌트
|
||||
*
|
||||
* 가이드:
|
||||
* 1. pagesPerGroup(예: 10)을 정의하여 한 번에 보여줄 페이지 갯수를 설정하세요.
|
||||
* 2. startPage(그룹 시작 페이지)와 endPage(그룹 끝 페이지)를 현재 페이지를 기준으로 계산하세요.
|
||||
* - 공식: Math.floor((currentPage - 1) / 10) * 10 + 1
|
||||
* 3. 반복문(for)을 사용하여 startPage부터 endPage까지의 번호를 배열에 담으세요.
|
||||
* 4. 이전 그룹, 다음 그룹, 개별 페이지 번호 클릭 시 onPageChange(번호)를 호출하도록 구현하세요.
|
||||
*/
|
||||
const Pagination: React.FC<PaginationProps> = ({ currentPage, totalPages, onPageChange }) => {
|
||||
// TODO: 페이징 그룹 로직을 구현하세요.
|
||||
const pagesPerGroup = 10;
|
||||
const startPage = Math.floor((currentPage - 1) / pagesPerGroup) * pagesPerGroup + 1 // 계산 필요
|
||||
const endPage = Math.min(startPage + 9, totalPages); // 계산 필요
|
||||
|
||||
const pageNumbers: number[] = [];
|
||||
// TODO: for문을 사용하여 pageNumbers 배열을 구성하세요.
|
||||
for(let i = startPage; i <= endPage; i++){
|
||||
pageNumbers.push(i);
|
||||
}
|
||||
|
||||
return (
|
||||
<nav aria-label="Page navigation">
|
||||
<ul className="pagination justify-content-center">
|
||||
{/* TODO: 이전 그룹 링크 (««) */}
|
||||
<li className={`page-item ${startPage === 1 ? 'disabled' : ''}`}>
|
||||
{/* 이전 페이지 그룹의 첫번재 페이지로 이동하기 */}
|
||||
<button className="page-link" onClick={() => {onPageChange(startPage - pagesPerGroup)}}>««</button>
|
||||
</li>
|
||||
|
||||
{/* TODO: 이전 페이지 링크 («) */}
|
||||
<li className={`page-item ${currentPage === 1 ? 'disabled' : ''}`}>
|
||||
<button className="page-link" onClick={() => {onPageChange(currentPage - 1)}}>«</button>
|
||||
</li>
|
||||
|
||||
{/* TODO: pageNumbers를 순회하며 번호 버튼을 생성하세요. */}
|
||||
{pageNumbers.map((number) => (
|
||||
<li key={number} className={`page-item ${currentPage === number ? 'active' : ''}`}>
|
||||
<button className="page-link" onClick={() => onPageChange(number)}>
|
||||
{number}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
|
||||
{/* TODO: 다음 페이지 및 다음 그룹 링크 (» 및 »») */}
|
||||
<li className={`page-item ${currentPage === totalPages ? 'disabled' : ''}`}>
|
||||
<button className="page-link" onClick={() => {onPageChange(currentPage + 1)}}>»</button>
|
||||
</li>
|
||||
|
||||
{/* 다음 페이지 그룹 이동 버튼 */}
|
||||
<li className={`page-item ${endPage === totalPages ? 'disabled' : ''}`}>
|
||||
{/* 다음 페이지 그룹의 첫번째 페이지 */}
|
||||
<button className="page-link" onClick={() => {onPageChange(endPage + 1)}}>»»</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="text-center mt-2 small text-muted">
|
||||
힌트: startPage = Math.floor((currentPage - 1) / 10) * 10 + 1
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pagination;
|
||||
@@ -0,0 +1,125 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { IBoardDetailResponse } from '../types/board';
|
||||
import { boardAPI } from '../api/boards';
|
||||
|
||||
const PostEditForm: React.FC = () => {
|
||||
// TODO: 폼 데이터를 위한 상태를 정의하세요 (useState)
|
||||
const [title, setTitle] = useState('');
|
||||
const [creaId, setCreaId] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [contents, setContents] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const id = String(useParams().id); // useParams 활용
|
||||
|
||||
// TODO: 폼 전송 핸들러를 작성하세요.
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const API_BASE_URL:string = import.meta.env.VITE_API_BASE_URL;
|
||||
const URL = `${API_BASE_URL}/board/api/detail/${id}`;
|
||||
try{
|
||||
await axios.post(URL, {
|
||||
title: title,
|
||||
password: password,
|
||||
contents: contents
|
||||
}).then(response=>{
|
||||
if(response.data.code === "0"){
|
||||
alert("게시글 수정에 성공했습니다.");
|
||||
navigate(`/post/${id}`);
|
||||
}else if(response.data.code === "-1"){
|
||||
alert("게시글 수정에 실패했습니다.");
|
||||
console.error(response.data.msg);
|
||||
}
|
||||
});
|
||||
}catch(e){
|
||||
alert("게시글 수정에 실패하였습니다.");
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPost = () => {
|
||||
const response = boardAPI.fetchPost(id);
|
||||
response.then(response=>{
|
||||
const post = response.data.detail;
|
||||
setTitle(post.title);
|
||||
setCreaId(post.creaId);
|
||||
setContents(post.contents);
|
||||
}).finally(()=>setLoading(false));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// fetchPost 호출 로직 구현
|
||||
fetchPost();
|
||||
}, [id]);
|
||||
|
||||
if (loading) return <div className="text-center mt-5">로딩 중...</div>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="mb-4">Edit Post</h2>
|
||||
<div className="card shadow-sm">
|
||||
<div className="card-body">
|
||||
<form /* TODO: onSubmit 핸들러 연결 */
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="title" className="form-label fw-bold">Title</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="title"
|
||||
required
|
||||
value={title}
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="creaId" className="form-label fw-bold">CreaId</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="creaId"
|
||||
value={creaId}
|
||||
required
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="password" className="form-label fw-bold">password</label>
|
||||
<input
|
||||
type="password"
|
||||
className="form-control"
|
||||
id="password"
|
||||
required
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="contents" className="form-label fw-bold">Content</label>
|
||||
<textarea
|
||||
className="form-control"
|
||||
id="contents"
|
||||
rows={5}
|
||||
value={contents}
|
||||
required
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setContents(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="d-flex justify-content-end gap-2">
|
||||
<button type="button" className="btn btn-secondary" onClick={() => navigate(`/post/${id}`)}>Cancel</button>
|
||||
<button type="submit" className="btn btn-primary px-4">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostEditForm;
|
||||
@@ -0,0 +1,117 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
* [실습 Phase 4] 게시글 작성 컴포넌트
|
||||
*
|
||||
* 가이드:
|
||||
* 1. useState를 사용하여 제목(title), 작성자(creaNm), 내용(contents) 상태를 각각 정의하세요.
|
||||
* 2. Input 태그의 value를 상태와 연결하고, onChange 이벤트를 통해 상태가 업데이트되도록 구현하세요. (제어 컴포넌트)
|
||||
* 3. 폼 제출 시(onSubmit) handleSubmit 함수를 실행하여 axios.post를 호출하세요.
|
||||
* - 엔드포인트: `${import.meta.env.VITE_API_BASE_URL}/board/api/write`
|
||||
* - 보낼 데이터: { title, creaNm, contents }
|
||||
* 4. 등록 성공 후, navigate('/')를 사용하여 홈(목록) 화면으로 이동하세요.
|
||||
*/
|
||||
const PostForm: React.FC = () => {
|
||||
// TODO: 폼 데이터를 위한 상태를 정의하세요 (useState)
|
||||
const [title, setTitle] = useState('');
|
||||
const [creaId, setCreaNm] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [contents, setContents] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
// TODO: 폼 전송 핸들러를 작성하세요.
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
/*
|
||||
try {
|
||||
await axios.post(URL, { ... });
|
||||
alert('성공!');
|
||||
navigate('/');
|
||||
} catch { ... }
|
||||
*/
|
||||
const API_BASE_URL:string = import.meta.env.VITE_API_BASE_URL;
|
||||
const URL = `${API_BASE_URL}/board/api/detail`;
|
||||
try{
|
||||
await axios.post(URL, {
|
||||
title: title,
|
||||
creaId: creaId,
|
||||
password: password,
|
||||
contents: contents
|
||||
});
|
||||
alert("게시글 생성에 성공하였습니다.");
|
||||
navigate("/");
|
||||
}catch(e){
|
||||
alert("게시글 생성에 실패하였습니다.");
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="mb-4">New Post</h2>
|
||||
<div className="card shadow-sm">
|
||||
<div className="card-body">
|
||||
<form /* TODO: onSubmit 핸들러 연결 */
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="title" className="form-label fw-bold">Title</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="title"
|
||||
required
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="creaId" className="form-label fw-bold">CreaId</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="creaId"
|
||||
required
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setCreaNm(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="password" className="form-label fw-bold">password</label>
|
||||
<input
|
||||
type="password"
|
||||
className="form-control"
|
||||
id="password"
|
||||
required
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="contents" className="form-label fw-bold">Content</label>
|
||||
<textarea
|
||||
className="form-control"
|
||||
id="contents"
|
||||
rows={5}
|
||||
required
|
||||
/* TODO: value와 onChange를 연결하세요 */
|
||||
onChange={(e) => setContents(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="d-flex justify-content-end gap-2">
|
||||
<button type="button" className="btn btn-secondary" onClick={() => navigate('/')}>Cancel</button>
|
||||
<button type="submit" className="btn btn-primary px-4">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 p-3 bg-light rounded text-center small">
|
||||
힌트: React에서는 입력값이 바뀔 때마다 상태를 업데이트하는 <strong>제어 컴포넌트(Controlled Component)</strong> 방식을 권장합니다.
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostForm;
|
||||
@@ -0,0 +1,113 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, Link, useNavigate } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { IBoardItem, IBoardDetailResponse, IBoardDeleteResponse, IBoardItem2 } from '../types/board';
|
||||
import { boardAPI } from '../api/boards';
|
||||
|
||||
/**
|
||||
* [실습 Phase 3] 게시글 상세 조회 컴포넌트
|
||||
*
|
||||
* 가이드:
|
||||
* 1. useParams Hook을 사용하여 URL에서 id 파라미터를 추출하세요.
|
||||
* 2. useState를 사용하여 post(상세 정보), loading(로딩 상태)를 관리하세요.
|
||||
* 3. useEffect와 fetchPost(상세조회 API 호출) 함수를 구현하세요.
|
||||
* - 엔드포인트: `${import.meta.env.VITE_API_BASE_URL}/board/api/detail/${id}`
|
||||
* 4. 조건부 렌더링을 사용하여 데이터가 없는 경우나 로딩 중일 때 표시할 화면을 작성하세요.
|
||||
* 5. 목록으로 돌아가기 버튼(useNavigate)과 수정/삭제 기능을 구상해 보세요.
|
||||
*/
|
||||
const PostView: React.FC = () => {
|
||||
// TODO: 게시글 데이터와 로딩 상태 관리를 위해 useState를 활용하세요.
|
||||
const [post, setPost] = useState<IBoardItem | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
|
||||
// TODO: URL 파라미터에서 ID를 받으세요. (useParams)
|
||||
const id = String(useParams().id); // useParams 활용
|
||||
|
||||
// TODO: 상세 데이터를 가져오는 함수를 작성하세요.
|
||||
const fetchPost = () => {
|
||||
/*
|
||||
axios.get<IBoardDetailResponse>(URL)
|
||||
.then(response => { ... })
|
||||
.finally(() => setLoading(false))
|
||||
*/
|
||||
const response = boardAPI.fetchPost(id);
|
||||
response.then(response=>{
|
||||
setPost(response.data.detail);
|
||||
}).finally(()=>setLoading(false));
|
||||
// const API_BASE_URL:string = import.meta.env.VITE_API_BASE_URL;
|
||||
// const URL = `${API_BASE_URL}/board/api/detail/${id}`;
|
||||
// axios.get<IBoardDetailResponse>(URL)
|
||||
// .then(response=>{
|
||||
// setPost(response.data.detail);
|
||||
// })
|
||||
// .finally(()=>setLoading(false));
|
||||
};
|
||||
|
||||
// 게시글 삭제 이벤트
|
||||
const handleDeletePost = (id: string)=>{
|
||||
// axios 삭제 요청
|
||||
const API_BASE_URL:string = import.meta.env.VITE_API_BASE_URL;
|
||||
const URL = `${API_BASE_URL}/board/api/detail/${id}`;
|
||||
|
||||
if(!confirm("게시글을 삭제하시겠습니까?")){
|
||||
return;
|
||||
}
|
||||
|
||||
axios.delete<IBoardDeleteResponse>(URL)
|
||||
.then(response=>{
|
||||
// code=1(삭제 성공), code=-1(삭제 실패)
|
||||
if(response.data.code === "1"){
|
||||
alert("게시글 삭제 성공했습니다.");
|
||||
navigate("/");
|
||||
}else if(response.data.code === "-1"){
|
||||
alert("게시글 삭제에 실패했습니다.");
|
||||
}
|
||||
})
|
||||
.finally(()=>setLoading(false));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// fetchPost 호출 로직 구현
|
||||
fetchPost();
|
||||
}, [id]);
|
||||
|
||||
// TODO: 렌더링 로직 (상태에 따라 화면 표시)
|
||||
if (loading) return <div className="text-center mt-5">로딩 중...</div>;
|
||||
if (!post) return <div className="alert alert-danger">게시글을 찾을 수 없습니다.</div>;
|
||||
|
||||
return (
|
||||
<div className="card shadow-sm">
|
||||
<div className="card-header bg-white py-3">
|
||||
{/* TODO: 게시글 제목 출력 */}
|
||||
<h2 className="mb-0">{post.title}</h2>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="mb-4 text-muted small">
|
||||
{/* TODO: 작성자, 날짜, 조회수 정보 바인딩 */}
|
||||
<span className="me-3"><strong>CreaId: </strong>{post.creaId}</span>
|
||||
<span><strong>Date: </strong> {post.creaDtm}</span>
|
||||
<span className="ms-3"><strong>Hits:</strong> {post.hitCnt}</span>
|
||||
</div>
|
||||
<hr />
|
||||
{/* TODO: 본문 내용 출력 (contents) */}
|
||||
<div className="my-4" style={{ minHeight: '200px', whiteSpace: 'pre-wrap' }}>
|
||||
{post.contents}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-footer bg-white py-3 d-flex justify-content-between">
|
||||
<Link to="/" className="btn btn-secondary">Back to List</Link>
|
||||
<div className="btn-group">
|
||||
{/* TODO: 수정/삭제 기능을 추가해 보세요. */}
|
||||
<button className="btn btn-outline-primary" onClick={() => navigate(`/edit/${id}`)}>Edit</button>
|
||||
<button className="btn btn-outline-danger" onClick={() => handleDeletePost(id)}>Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-2 small text-muted text-center border-top">
|
||||
힌트: useNavigate()를 사용하면 프로그래밍 방식으로 페이지를 이동할 수 있습니다.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostView;
|
||||
@@ -0,0 +1,65 @@
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import './index.css'
|
||||
import App from './App'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
export interface IBoardItem {
|
||||
idx: number | string;
|
||||
title: string;
|
||||
contents: string;
|
||||
creaId: string
|
||||
creaNm: string;
|
||||
creaDtm: string;
|
||||
hitCnt: number | string;
|
||||
rnum?: number;
|
||||
}
|
||||
|
||||
export interface IBoardItem2{
|
||||
idx: number | string;
|
||||
title: string;
|
||||
contents: string;
|
||||
creaId: string;
|
||||
creaDtm: string;
|
||||
hitCnt: number | string;
|
||||
rnum?: number;
|
||||
}
|
||||
|
||||
export interface IBoardResponse {
|
||||
list: IBoardItem[];
|
||||
totalpage: number;
|
||||
}
|
||||
|
||||
export interface IBoardDetailResponse {
|
||||
detail: IBoardItem;
|
||||
}
|
||||
|
||||
export interface IBoardDeleteResponse{
|
||||
code: String,
|
||||
msg: String
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
interface ImportMetaEnv{
|
||||
readonly VITE_API_BASE_URL: string;
|
||||
}
|
||||
|
||||
interface ImportMeta{
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.js", "src/**/*.d.ts"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
VITE_API_BASE_URL=http://localhost:8080/RestBoard
|
||||
@@ -0,0 +1,12 @@
|
||||
# React + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||
@@ -0,0 +1,29 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
||||
},
|
||||
},
|
||||
])
|
||||
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "react_board",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.12.2",
|
||||
"bootstrap": "^5.3.8",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router-dom": "^7.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/react": "^19.1.13",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@vitejs/plugin-react": "^5.0.2",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"globals": "^16.4.0",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^7.1.6"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import Header from './components/Header';
|
||||
import BoardList from './components/BoardList';
|
||||
import PostView from './components/PostView';
|
||||
import PostForm from './components/PostForm';
|
||||
import './App.css';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Header />
|
||||
<div className="container mt-4">
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="/" element={<BoardList />} />
|
||||
<Route path="/post/:id" element={<PostView />} />
|
||||
<Route path="/new" element={<PostForm />} />
|
||||
</Routes>
|
||||
</main>
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,31 @@
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.pagination button {
|
||||
margin: 0 5px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.pagination button:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.pagination button:disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pagination button.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,118 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import Pagination from './Pagination';
|
||||
import { IBoardItem, IBoardResponse } from '../types/board';
|
||||
|
||||
const BoardList: React.FC = () => {
|
||||
const [posts, setPosts] = useState<IBoardItem[]>([]);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [submittedSearchTerm, setSubmittedSearchTerm] = useState('');
|
||||
const [searchType, setSearchType] = useState('title');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(1);
|
||||
|
||||
const handleSearch = () => {
|
||||
setSubmittedSearchTerm(searchTerm);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleSearch();
|
||||
}
|
||||
};
|
||||
|
||||
const retriveBoard = (type?: string, keyword?: string) => {
|
||||
axios.get<IBoardResponse>(`${import.meta.env.VITE_API_BASE_URL}/board/api/list`, {
|
||||
params: {
|
||||
type: type,
|
||||
keyword: keyword,
|
||||
page: currentPage,
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
setPosts(response.data.list);
|
||||
setTotalPages(response.data.totalpage);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching board list:', error);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
retriveBoard(searchType, submittedSearchTerm);
|
||||
}, [submittedSearchTerm, currentPage]);
|
||||
|
||||
const handlePageChange = (page: number) => setCurrentPage(page);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="mb-4">Board</h2>
|
||||
|
||||
<div className="row justify-content-between mb-3">
|
||||
<div className="col-md-auto">
|
||||
<Link to="/new" className="btn btn-primary">New Post</Link>
|
||||
</div>
|
||||
<div className="col-md-7">
|
||||
<div className="input-group">
|
||||
<select
|
||||
className="form-select"
|
||||
style={{ flex: '0 0 120px' }}
|
||||
value={searchType}
|
||||
onChange={e => setSearchType(e.target.value)}
|
||||
>
|
||||
<option value="title">Title</option>
|
||||
<option value="content">Content</option>
|
||||
<option value="author">Author</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={`Search by ${searchType}...`}
|
||||
value={searchTerm}
|
||||
onChange={e => setSearchTerm(e.target.value)}
|
||||
onKeyDown={handleKeyPress}
|
||||
/>
|
||||
<button className="btn btn-outline-secondary" type="button" onClick={handleSearch}>Search</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="table-responsive">
|
||||
<table className="table table-hover">
|
||||
<thead className="table-light">
|
||||
<tr>
|
||||
<th>No.</th>
|
||||
<th>Title</th>
|
||||
<th>Author</th>
|
||||
<th>Date</th>
|
||||
<th>Hits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{posts.map((post) => (
|
||||
<tr key={post.idx}>
|
||||
<td>{post.rnum}</td>
|
||||
<td>
|
||||
<Link to={`/post/${post.idx}`}>{post.title}</Link>
|
||||
</td>
|
||||
<td>{post.creaNm}</td>
|
||||
<td>{post.creaDtm}</td>
|
||||
<td>{post.hitCnt}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPageChange={handlePageChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoardList;
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
return (
|
||||
<header>
|
||||
<nav className="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm">
|
||||
<div className="container">
|
||||
<Link className="navbar-brand fw-bold" to="/">React Board</Link>
|
||||
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span className="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div className="collapse navbar-collapse" id="navbarNav">
|
||||
<ul className="navbar-nav ms-auto">
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/">Home</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/new">New Post</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,75 @@
|
||||
import React from 'react';
|
||||
|
||||
interface PaginationProps {
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
onPageChange: (page: number) => void;
|
||||
}
|
||||
|
||||
const Pagination: React.FC<PaginationProps> = ({ currentPage, totalPages, onPageChange }) => {
|
||||
const pagesPerGroup = 10;
|
||||
const startPage = Math.floor((currentPage - 1) / pagesPerGroup) * pagesPerGroup + 1;
|
||||
const endPage = Math.min(startPage + pagesPerGroup - 1, totalPages);
|
||||
|
||||
const pageNumbers: number[] = [];
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
pageNumbers.push(i);
|
||||
}
|
||||
|
||||
return (
|
||||
<nav aria-label="Page navigation">
|
||||
<ul className="pagination justify-content-center">
|
||||
<li className={`page-item ${startPage === 1 ? 'disabled' : ''}`}>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => onPageChange(Math.max(startPage - pagesPerGroup, 1))}
|
||||
aria-label="Previous Group"
|
||||
>
|
||||
<span aria-hidden="true">««</span>
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${currentPage === 1 ? 'disabled' : ''}`}>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => onPageChange(Math.max(currentPage - 1, 1))}
|
||||
aria-label="Previous"
|
||||
>
|
||||
<span aria-hidden="true">«</span>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
{pageNumbers.map((number) => (
|
||||
<li key={number} className={`page-item ${currentPage === number ? 'active' : ''}`}>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => onPageChange(number)}
|
||||
>
|
||||
{number}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
|
||||
<li className={`page-item ${currentPage === totalPages ? 'disabled' : ''}`}>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => onPageChange(Math.min(currentPage + 1, totalPages))}
|
||||
aria-label="Next"
|
||||
>
|
||||
<span aria-hidden="true">»</span>
|
||||
</button>
|
||||
</li>
|
||||
<li className={`page-item ${endPage === totalPages ? 'disabled' : ''}`}>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => onPageChange(Math.min(startPage + pagesPerGroup, totalPages))}
|
||||
aria-label="Next Group"
|
||||
>
|
||||
<span aria-hidden="true">»»</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Pagination;
|
||||
@@ -0,0 +1,74 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
|
||||
const PostForm: React.FC = () => {
|
||||
const [title, setTitle] = useState('');
|
||||
const [creaNm, setCreaNm] = useState('');
|
||||
const [contents, setContents] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
// Logic for API call
|
||||
// await axios.post(`${import.meta.env.VITE_API_BASE_URL}/board/api/write`, { title, creaNm, contents });
|
||||
console.log({ title, creaNm, contents });
|
||||
alert('Post submitted successfully!');
|
||||
navigate('/');
|
||||
} catch (error) {
|
||||
console.error('Error submitting post:', error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="mb-4">New Post</h2>
|
||||
<div className="card shadow-sm">
|
||||
<div className="card-body">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="title" className="form-label fw-bold">Title</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="title"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="creaNm" className="form-label fw-bold">Author</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="creaNm"
|
||||
value={creaNm}
|
||||
onChange={(e) => setCreaNm(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="contents" className="form-label fw-bold">Content</label>
|
||||
<textarea
|
||||
className="form-control"
|
||||
id="contents"
|
||||
rows={5}
|
||||
value={contents}
|
||||
onChange={(e) => setContents(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="d-flex justify-content-end gap-2">
|
||||
<button type="button" className="btn btn-secondary" onClick={() => navigate('/')}>Cancel</button>
|
||||
<button type="submit" className="btn btn-primary px-4">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostForm;
|
||||
@@ -0,0 +1,66 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, Link, useNavigate } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { IBoardItem, IBoardDetailResponse } from '../types/board';
|
||||
|
||||
const PostView: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const [post, setPost] = useState<IBoardItem | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchPost = async () => {
|
||||
try {
|
||||
const response = await axios.get<IBoardDetailResponse>(`${import.meta.env.VITE_API_BASE_URL}/board/api/detail/${id}`);
|
||||
setPost(response.data.detail);
|
||||
} catch (error) {
|
||||
console.error('Error fetching post detail:', error);
|
||||
// Fallback for demo if API fails
|
||||
setPost({
|
||||
idx: id || '',
|
||||
title: `Post ${id}`,
|
||||
creaNm: `User${id}`,
|
||||
contents: `This is the full content of post ${id}.`,
|
||||
creaDtm: '2025-09-16',
|
||||
hitCnt: 0
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPost();
|
||||
}, [id]);
|
||||
|
||||
if (loading) return <div className="text-center mt-5"><div className="spinner-border" role="status"></div></div>;
|
||||
if (!post) return <div className="alert alert-danger">Post not found.</div>;
|
||||
|
||||
return (
|
||||
<div className="card shadow-sm">
|
||||
<div className="card-header bg-white py-3">
|
||||
<h2 className="mb-0">{post.title}</h2>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="mb-4 text-muted small">
|
||||
<span className="me-3"><strong>Author:</strong> {post.creaNm}</span>
|
||||
<span><strong>Date:</strong> {post.creaDtm}</span>
|
||||
<span className="ms-3"><strong>Hits:</strong> {post.hitCnt}</span>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="my-4" style={{ minHeight: '200px', whiteSpace: 'pre-wrap' }}>
|
||||
{post.contents}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-footer bg-white py-3 d-flex justify-content-between">
|
||||
<Link to="/" className="btn btn-secondary">Back to List</Link>
|
||||
<div className="btn-group">
|
||||
<button className="btn btn-outline-primary" onClick={() => alert('Edit function coming soon')}>Edit</button>
|
||||
<button className="btn btn-outline-danger" onClick={() => alert('Delete function coming soon')}>Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostView;
|
||||
@@ -0,0 +1,65 @@
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
import './index.css'
|
||||
import App from './App'
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
export interface IBoardItem {
|
||||
idx: number | string;
|
||||
title: string;
|
||||
contents: string;
|
||||
creaNm: string;
|
||||
creaDtm: string;
|
||||
hitCnt: number | string;
|
||||
rnum?: number;
|
||||
}
|
||||
|
||||
export interface IBoardResponse {
|
||||
list: IBoardItem[];
|
||||
totalpage: number;
|
||||
}
|
||||
|
||||
export interface IBoardDetailResponse {
|
||||
detail: IBoardItem;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.js"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
})
|
||||
@@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,70 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "tic-tac-toe",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/dom": "^10.4.2",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.3",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^19.3.1",
|
||||
"react-dom": "^19.3.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,38 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import { useState } from "react";
|
||||
|
||||
function Square({value, onSquareClick}){
|
||||
return (
|
||||
<button className="square" onClick={onSquareClick}>{value}</button>
|
||||
);
|
||||
}
|
||||
|
||||
function Board({xIsNext, squares, onPlay}){
|
||||
|
||||
function handleClick(i){
|
||||
if(calculateWinner(squares) || squares[i]){
|
||||
return;
|
||||
}
|
||||
const nextSquares = squares.slice();
|
||||
if(xIsNext){
|
||||
nextSquares[i] = "X";
|
||||
}else{
|
||||
nextSquares[i] = "O";
|
||||
}
|
||||
onPlay(nextSquares);
|
||||
}
|
||||
|
||||
const winner = calculateWinner(squares);
|
||||
let status;
|
||||
if(winner){
|
||||
status = "Winner: " + winner;
|
||||
}else{
|
||||
status = "Next Player: " + (xIsNext ? "X" : "O");
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="status">{status}</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[0]} onSquareClick={()=>handleClick(0)}/>
|
||||
<Square value={squares[1]} onSquareClick={()=>handleClick(1)}/>
|
||||
<Square value={squares[2]} onSquareClick={()=>handleClick(2)}/>
|
||||
</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[3]} onSquareClick={()=>handleClick(3)}/>
|
||||
<Square value={squares[4]} onSquareClick={()=>handleClick(4)}/>
|
||||
<Square value={squares[5]} onSquareClick={()=>handleClick(5)}/>
|
||||
</div>
|
||||
<div className="board-row">
|
||||
<Square value={squares[6]} onSquareClick={()=>handleClick(6)}/>
|
||||
<Square value={squares[7]} onSquareClick={()=>handleClick(7)}/>
|
||||
<Square value={squares[8]} onSquareClick={()=>handleClick(8)}/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function calculateWinner(squares){
|
||||
const lines = [
|
||||
[0, 1, 2],
|
||||
[3, 4, 5],
|
||||
[6, 7, 8],
|
||||
[0, 3, 6],
|
||||
[1, 4, 7],
|
||||
[2, 5, 8],
|
||||
[0, 4, 8],
|
||||
[2, 4, 6]
|
||||
];
|
||||
for(let i = 0; i < lines.length; i++){
|
||||
const [a, b, c] = lines[i];
|
||||
if(squares[a] && squares[a] === squares[b] && squares[a] === squares[c]){
|
||||
return squares[a];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function Game(){
|
||||
const [history, setHistory] = useState([Array(9).fill(null)]);
|
||||
const [currentMove, setCurrentMove] = useState(0);
|
||||
const xIsNext = currentMove % 2 === 0;
|
||||
const currentSquares = history[currentMove];
|
||||
|
||||
function handlePlay(nextSquares){
|
||||
const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];
|
||||
setHistory(nextHistory);
|
||||
setCurrentMove(nextHistory.length - 1);
|
||||
}
|
||||
|
||||
function jumpTo(nextMove){
|
||||
setCurrentMove(nextMove);
|
||||
}
|
||||
|
||||
const moves = history.map((squares, move)=>{
|
||||
let description;
|
||||
if(move > 0){
|
||||
description = "Go to move #" + move;
|
||||
}else{
|
||||
description = "Go to game start";
|
||||
}
|
||||
return (
|
||||
<li key={move}>
|
||||
<button onClick={()=>jumpTo(move)}>{description}</button>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="game">
|
||||
<div className="game-board">
|
||||
<Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay}/>
|
||||
</div>
|
||||
<div className="game-info">
|
||||
<ol>{moves}</ol>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
@@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
@@ -0,0 +1,6 @@
|
||||
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -0,0 +1 @@
|
||||
VITE_API_BASE_URL=http://localhost:8080/RestBoard
|
||||
@@ -0,0 +1,30 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# vue_board
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -0,0 +1,19 @@
|
||||
import js from '@eslint/js'
|
||||
import pluginVue from 'eslint-plugin-vue'
|
||||
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
|
||||
|
||||
export default [
|
||||
{
|
||||
name: 'app/files-to-lint',
|
||||
files: ['**/*.{js,mjs,jsx,vue}'],
|
||||
},
|
||||
|
||||
{
|
||||
name: 'app/files-to-ignore',
|
||||
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
|
||||
},
|
||||
|
||||
js.configs.recommended,
|
||||
...pluginVue.configs['flat/essential'],
|
||||
skipFormatting,
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "vue_board",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build",
|
||||
"lint": "eslint . --fix",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@tsconfig/node22": "^22.0.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
"@vue/eslint-config-prettier": "^10.1.0",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"npm-run-all2": "^7.0.2",
|
||||
"prettier": "^3.3.3",
|
||||
"typescript": "~5.7.3",
|
||||
"vite": "^6.0.5",
|
||||
"vite-plugin-vue-devtools": "^7.6.8",
|
||||
"vue-tsc": "^2.2.4"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,235 @@
|
||||
/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
|
||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
|
||||
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
||||
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
||||
a{background-color:transparent}a:active,a:hover{outline-width:0}
|
||||
abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
||||
b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
|
||||
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}
|
||||
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
|
||||
button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
|
||||
button,input{overflow:visible}button,select{text-transform:none}
|
||||
button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}
|
||||
button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
||||
button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
||||
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
||||
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
||||
[type=checkbox],[type=radio]{padding:0}
|
||||
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
||||
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
|
||||
[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
||||
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
||||
/* End extract */
|
||||
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
|
||||
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
|
||||
.w3-serif{font-family:serif}.w3-sans-serif{font-family:sans-serif}.w3-cursive{font-family:cursive}.w3-monospace{font-family:monospace}
|
||||
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
||||
hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
||||
.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit}
|
||||
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
|
||||
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
||||
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
|
||||
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
||||
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
||||
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
||||
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
||||
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
|
||||
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
||||
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
|
||||
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
|
||||
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
|
||||
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
||||
.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
|
||||
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
||||
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
|
||||
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
|
||||
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
||||
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
|
||||
.w3-main,#main{transition:margin-left .4s}
|
||||
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
||||
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
|
||||
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
||||
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
|
||||
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
||||
.w3-bar .w3-button{white-space:normal}
|
||||
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
|
||||
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
|
||||
.w3-responsive{display:block;overflow-x:auto}
|
||||
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
|
||||
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
|
||||
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
||||
.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
|
||||
.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
|
||||
.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
|
||||
@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
|
||||
.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
|
||||
.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
|
||||
@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
|
||||
.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
|
||||
.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
|
||||
.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
|
||||
.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
|
||||
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
|
||||
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
|
||||
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
||||
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
|
||||
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
||||
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
|
||||
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
||||
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
||||
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
||||
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
||||
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
||||
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
||||
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
||||
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
||||
.w3-display-position{position:absolute}
|
||||
.w3-circle{border-radius:50%}
|
||||
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
|
||||
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
|
||||
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
|
||||
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
|
||||
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
||||
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
||||
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
||||
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
|
||||
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
|
||||
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
|
||||
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
|
||||
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
|
||||
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
||||
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
||||
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
||||
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
||||
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
||||
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
||||
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
||||
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
||||
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
|
||||
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
||||
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
||||
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
|
||||
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
||||
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
||||
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
||||
.w3-padding-top-64{padding-top:64px!important}.w3-padding-top-48{padding-top:48px!important}
|
||||
.w3-padding-top-32{padding-top:32px!important}.w3-padding-top-24{padding-top:24px!important}
|
||||
.w3-left{float:left!important}.w3-right{float:right!important}
|
||||
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||
.w3-hover-none:hover{box-shadow:none!important}
|
||||
/* Colors */
|
||||
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
||||
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
||||
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
||||
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
||||
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
||||
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
||||
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
||||
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
||||
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
||||
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
|
||||
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
|
||||
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
||||
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
|
||||
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
|
||||
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
|
||||
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
|
||||
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
||||
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
|
||||
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
|
||||
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
|
||||
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
|
||||
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
|
||||
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
|
||||
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
|
||||
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
|
||||
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
|
||||
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
||||
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
|
||||
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
|
||||
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
|
||||
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
||||
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
||||
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
||||
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
||||
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
||||
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
|
||||
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
|
||||
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
||||
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
|
||||
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
|
||||
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
|
||||
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
|
||||
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
||||
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
|
||||
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
|
||||
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
|
||||
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
|
||||
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
|
||||
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
|
||||
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
|
||||
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
|
||||
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
|
||||
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
||||
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
|
||||
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
|
||||
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
||||
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
||||
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
||||
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
|
||||
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||
@@ -0,0 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
|
||||
const menuDisplay = ref(false);
|
||||
function w3_open(){
|
||||
menuDisplay.value = true;
|
||||
}
|
||||
function w3_close(){
|
||||
menuDisplay.value = false;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Sidebar (hidden by default) -->
|
||||
<nav class="w3-sidebar w3-bar-block w3-card w3-top w3-xlarge w3-animate-left" :style="{'display':menuDisplay === true?'block':'none', 'z-index':'2', 'width':'40%', 'min-width':'300px'}" id="mySidebar">
|
||||
<a href="javascript:void(0)" @click.prevent="w3_close"
|
||||
class="w3-bar-item w3-button">Close Menu</a>
|
||||
<RouterLink to="/" @click.prevent="w3_close" class="w3-bar-item w3-button">Home</RouterLink>
|
||||
<RouterLink to="/board" @click.prevent="w3_close" class="w3-bar-item w3-button">Board</RouterLink>
|
||||
</nav>
|
||||
|
||||
<!-- Top menu -->
|
||||
<div class="w3-top">
|
||||
<div class="w3-white w3-xlarge" style="max-width:1200px;margin:auto">
|
||||
<div class="w3-button w3-padding-16 w3-left" @click.prevent="w3_open">☰</div>
|
||||
<div class="w3-right w3-padding-16"></div>
|
||||
<div class="w3-center w3-padding-16">Board</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w3-main w3-content w3-padding" style="max-width:1200px;margin-top:100px">
|
||||
<RouterView />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||