longpoll api update, waiting list update, chat update, online status
This commit is contained in:
parent
89fde1afc9
commit
ff0fbe06ac
5
pom.xml
5
pom.xml
@ -75,6 +75,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -1,30 +1,233 @@
|
||||
package com.alterdekim.game.component;
|
||||
|
||||
import com.alterdekim.game.dto.LongPollResult;
|
||||
import com.alterdekim.game.dto.*;
|
||||
import com.alterdekim.game.entities.Chat;
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import com.alterdekim.game.entities.RoomPlayer;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import com.alterdekim.game.service.*;
|
||||
import com.alterdekim.game.util.Hash;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class LongPoll {
|
||||
|
||||
private final BlockingQueue<LongPollingSession> longPollingQueue = new ArrayBlockingQueue<>(100);
|
||||
private final Integer iterations = 6;
|
||||
|
||||
@Scheduled(fixedRate = 5000)
|
||||
private final BlockingQueue<LongPollingSession> longPollingQueue = new ArrayBlockingQueue<>(100);
|
||||
private final ConcurrentHashMap<Long, LongPollConfig> map = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private UserServiceImpl userService;
|
||||
|
||||
@Autowired
|
||||
private ChatServiceImpl chatService;
|
||||
|
||||
@Autowired
|
||||
private RoomServiceImpl roomService;
|
||||
|
||||
@Autowired
|
||||
private RoomPlayerServiceImpl roomPlayerService;
|
||||
|
||||
@Autowired
|
||||
private FriendServiceImpl friendService;
|
||||
|
||||
@Scheduled(fixedRate = 3000)
|
||||
private void longPoll() {
|
||||
getLongPollingQueue().removeIf(e -> e.getDeferredResult().isSetOrExpired());
|
||||
roomService.clearEmptyRooms();
|
||||
getMap().keySet().forEach(k -> {
|
||||
if( (System.currentTimeMillis() - getMap().get(k).getLastRequest()) >= 60000 ) getMap().remove(k);
|
||||
});
|
||||
getLongPollingQueue().forEach(longPollingSession -> {
|
||||
try {
|
||||
longPollingSession.getDeferredResult().setResult(new LongPollResult());
|
||||
if( !map.containsKey(longPollingSession.getUserId())) map.put(longPollingSession.getUserId(), new LongPollConfig(0L,new ArrayList<>(), 0, Hash.rnd(), new ArrayList<>(), System.currentTimeMillis()));
|
||||
LongPollConfig config = map.get(longPollingSession.getUserId());
|
||||
LongPollResult result = process(longPollingSession.getUserId(), config);
|
||||
if( !result.getRooms().isEmpty() )
|
||||
config.setRooms(result.getRooms().stream().filter(r -> r.getAction() == RoomResultState.ADD_CHANGE).map(r -> new RoomResult(r.getId(), r.getPlayerCount(), r.getPlayers())).collect(Collectors.toList()));
|
||||
if( !result.getFriends().isEmpty() )
|
||||
config.setFriends_online(result.getFriends().stream().filter(r -> r.getAction() == FriendState.ADD).map(r -> new UserResult(r.getId(), r.getUsername())).collect(Collectors.toList()));
|
||||
|
||||
config.setSession_pass(config.getSession_pass()+1);
|
||||
|
||||
if( !result.getFriends().isEmpty() || !result.getRooms().isEmpty() || !result.getMessages().isEmpty() || config.getSession_pass() >= iterations) {
|
||||
longPollingSession.getDeferredResult().setResult(result);
|
||||
config.setSession_pass(0);
|
||||
}
|
||||
map.put(longPollingSession.getUserId(), config);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
getLongPollingQueue().removeIf(e -> e.getDeferredResult().isSetOrExpired());
|
||||
}
|
||||
|
||||
private LongPollResult process(Long userId, LongPollConfig config) {
|
||||
userService.updateOnline(userId);
|
||||
|
||||
Integer onlineCount = userService.countByIsOnline();
|
||||
List<Chat> results;
|
||||
List<UserResult> users = new ArrayList<>();
|
||||
List<RoomResult> clientRooms = config.getRooms();
|
||||
List<RoomResultV2> roomResults = new ArrayList<>();
|
||||
List<UserResult> clientFriends = config.getFriends_online();
|
||||
List<FriendResult> friendsResult = new ArrayList<>();
|
||||
|
||||
results = chatService.getAfterLastChatId(config.getLast_chat_id());
|
||||
|
||||
if( !results.isEmpty() ) {
|
||||
users = results.stream()
|
||||
.map(Chat::getUserId)
|
||||
.distinct()
|
||||
.map(l -> userService.findById(l))
|
||||
.map(u -> new UserResult(u.getId(), u.getUsername()))
|
||||
.collect(Collectors.toList());
|
||||
results = results.stream().peek(c -> {
|
||||
String message = c.getMessage();
|
||||
for (int i = 0; i < message.length(); i++) {
|
||||
if (message.charAt(i) == '@') {
|
||||
int u = message.substring(i).indexOf(' ') + i;
|
||||
String username = message.substring(i + 1, u);
|
||||
User user = userService.findByUsername(username);
|
||||
if (user != null) {
|
||||
Long uid = user.getId();
|
||||
message = message.substring(0, i) + "<a href=\"/profile/" + uid + "\" class=\"chat-history-user\"><span class=\"_nick\">" + username + "</span></a>" + message.substring(u + 1);
|
||||
} else {
|
||||
message = message.substring(0, i) + username + message.substring(u + 1);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
c.setMessage(message);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
if( !clientRooms.isEmpty() ) {
|
||||
List<RoomResult> rooms = roomService.getAllActive().stream()
|
||||
.map( r -> new RoomResult(r.getId(), r.getPlayerCount(), roomPlayerService.findByRoomId(r.getId()).stream()
|
||||
.map(p -> userService.findById(p.getUserId()))
|
||||
.map(p -> new UserResult(p.getId(), p.getUsername()))
|
||||
.collect(Collectors.toList())))
|
||||
.collect(Collectors.toList());
|
||||
if( !isEqualListRoom(rooms, clientRooms) ) {
|
||||
List<RoomResult> rr = new ArrayList<>(rooms);
|
||||
List<RoomResultV2> resultV2List = new ArrayList<>();
|
||||
for( RoomResult r : clientRooms ) {
|
||||
if( rooms.stream().noneMatch(t -> t.getId().longValue() == r.getId().longValue()) ) {
|
||||
resultV2List.add(new RoomResultV2(RoomResultState.REMOVE, r.getId(), r.getPlayerCount(), r.getPlayers()));
|
||||
} else {
|
||||
RoomResult r1 = rooms.stream().filter( t -> t.getId().longValue() == r.getId().longValue()).findFirst().get();
|
||||
if( !isEqual(r, r1) ) {
|
||||
resultV2List.add(new RoomResultV2(RoomResultState.ADD_CHANGE, r1.getId(), r1.getPlayerCount(), r1.getPlayers()));
|
||||
}
|
||||
rr.remove(r1);
|
||||
}
|
||||
}
|
||||
for( RoomResult r : rr ) {
|
||||
resultV2List.add(new RoomResultV2(RoomResultState.ADD_CHANGE, r.getId(), r.getPlayerCount(), r.getPlayers()));
|
||||
}
|
||||
roomResults = resultV2List.stream().sorted(Comparator.comparingLong(RoomResultV2::getId)).collect(Collectors.toList());
|
||||
} else {
|
||||
roomResults = new ArrayList<>();
|
||||
}
|
||||
} else {
|
||||
List<Room> rooms = roomService.getAllActive();
|
||||
roomResults = rooms.stream()
|
||||
.map( r -> new RoomResultV2(RoomResultState.ADD_CHANGE, r.getId(), r.getPlayerCount(), roomPlayerService.findByRoomId(r.getId()).stream()
|
||||
.map(p -> userService.findById(p.getUserId()))
|
||||
.map(p -> new UserResult(p.getId(), p.getUsername()))
|
||||
.collect(Collectors.toList())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if( !clientFriends.isEmpty() ) {
|
||||
List<UserResult> userResults = friendService.getFriendsOfUserId(userId)
|
||||
.stream()
|
||||
.map(id -> userService.findById(id))
|
||||
.map(u -> new UserResult(u.getId(), u.getUsername()))
|
||||
.filter(f -> getMap().keySet().stream().anyMatch(l -> l.longValue() == f.getId().longValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if( !isEqualListUser(userResults, clientFriends) ) {
|
||||
List<UserResult> urr = new ArrayList<>(userResults);
|
||||
List<FriendResult> fr = new ArrayList<>();
|
||||
for( UserResult r : clientFriends ) {
|
||||
if( userResults.stream().noneMatch(t -> t.getId().longValue() == r.getId().longValue()) ) {
|
||||
fr.add(new FriendResult(FriendState.REMOVE, r.getId(), r.getUsername()));
|
||||
} else {
|
||||
UserResult r1 = userResults.stream().filter( t -> t.getId().longValue() == r.getId().longValue()).findFirst().get();
|
||||
if( !isEqualUser(r, r1) ) {
|
||||
fr.add(new FriendResult(FriendState.ADD, r1.getId(), r1.getUsername()));
|
||||
}
|
||||
urr.remove(r1);
|
||||
}
|
||||
}
|
||||
for( UserResult r : urr ) {
|
||||
fr.add(new FriendResult(FriendState.ADD, r.getId(), r.getUsername()));
|
||||
}
|
||||
friendsResult = fr.stream().sorted(Comparator.comparingLong(FriendResult::getId)).collect(Collectors.toList());
|
||||
} else {
|
||||
friendsResult = new ArrayList<>();
|
||||
}
|
||||
} else {
|
||||
friendsResult = friendService.getFriendsOfUserId(userId)
|
||||
.stream()
|
||||
.map(id -> userService.findById(id))
|
||||
.filter(f -> getMap().keySet().stream().anyMatch(l -> l.longValue() == f.getId().longValue()))
|
||||
.map(f -> new FriendResult(FriendState.ADD, f.getId(), f.getUsername()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return new LongPollResult(onlineCount, results, users, roomResults, friendsResult);
|
||||
}
|
||||
|
||||
private Boolean isEqual(RoomResult r1, RoomResult r2) {
|
||||
return r1.getId().longValue() == r2.getId().longValue() &&
|
||||
r1.getPlayerCount().intValue() == r2.getPlayerCount().intValue() &&
|
||||
isEqualListUser(r1.getPlayers(), r2.getPlayers());
|
||||
}
|
||||
|
||||
private Boolean isEqualUser(UserResult r1, UserResult r2) {
|
||||
return r1.getId().longValue() == r2.getId().longValue() &&
|
||||
r1.getUsername().equals(r2.getUsername());
|
||||
}
|
||||
|
||||
private Boolean isEqualListRoom(List<RoomResult> r1, List<RoomResult> r2) {
|
||||
r1 = r1.stream().sorted(Comparator.comparingLong(RoomResult::getId)).collect(Collectors.toList());
|
||||
r2 = r2.stream().sorted(Comparator.comparingLong(RoomResult::getId)).collect(Collectors.toList());
|
||||
if( r1.size() != r2.size() ) return false;
|
||||
for( int i = 0; i < r1.size(); i++ ) {
|
||||
if( !isEqual(r1.get(i), r2.get(i)) ) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean isEqualListUser(List<UserResult> r1, List<UserResult> r2) {
|
||||
r1 = r1.stream().sorted(Comparator.comparingLong(UserResult::getId)).collect(Collectors.toList());
|
||||
r2 = r2.stream().sorted(Comparator.comparingLong(UserResult::getId)).collect(Collectors.toList());
|
||||
if( r1.size() != r2.size() ) return false;
|
||||
for( int i = 0; i < r1.size(); i++ ) {
|
||||
if( r1.get(i).getId().longValue() != r2.get(i).getId().longValue() ||
|
||||
!r1.get(i).getUsername().equals(r2.get(i).getUsername()) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package com.alterdekim.game.component;
|
||||
|
||||
import com.alterdekim.game.dto.RoomResult;
|
||||
import com.alterdekim.game.dto.UserResult;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class LongPollConfig {
|
||||
private Long last_chat_id;
|
||||
private List<RoomResult> rooms;
|
||||
private Integer session_pass;
|
||||
private String poll_token;
|
||||
private List<UserResult> friends_online;
|
||||
private Long lastRequest;
|
||||
}
|
@ -7,8 +7,7 @@ import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
|
||||
public class LongPollingSession {
|
||||
private Long last_chat_id;
|
||||
private Long userId;
|
||||
private DeferredResult<LongPollResult> deferredResult;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.game.controller;
|
||||
|
||||
|
||||
import com.alterdekim.game.component.LongPoll;
|
||||
import com.alterdekim.game.component.LongPollConfig;
|
||||
import com.alterdekim.game.component.LongPollingSession;
|
||||
import com.alterdekim.game.dto.*;
|
||||
import com.alterdekim.game.entities.Chat;
|
||||
@ -20,10 +21,9 @@ import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@ -51,17 +51,6 @@ public class APIController {
|
||||
@Autowired
|
||||
private LongPoll longPoll;
|
||||
|
||||
@GetMapping("/api/v1/games/list")
|
||||
public ResponseEntity<List<RoomResult>> gamesList() {
|
||||
List<RoomResult> results = roomService.getAll()
|
||||
.stream()
|
||||
.map(room -> new RoomResult(room.getId(), room.getPlayerCount(), roomPlayerService.findByRoomId(room.getId()).stream()
|
||||
.map(p -> userService.findById(p.getId()))
|
||||
.map(p -> new UserResult(p.getId(), p.getUsername())).collect(Collectors.toList())))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(results);
|
||||
}
|
||||
|
||||
@GetMapping("/api/v1/chat/history/{count}/")
|
||||
public ResponseEntity<ChatResult> chatList(@PathVariable Integer count ) {
|
||||
List<Chat> results = chatService.getLastChats(count);
|
||||
@ -132,11 +121,24 @@ public class APIController {
|
||||
return ResponseEntity.accepted().build();
|
||||
}
|
||||
|
||||
@GetMapping("/async/notify/get/")
|
||||
@PostMapping("/api/v1/rooms/create/")
|
||||
public ResponseEntity<String> createRoom( @RequestParam("is_private") Boolean is_private,
|
||||
@RequestParam("players_count") Integer players_count) {
|
||||
if( !(players_count >= 2 && players_count <= 5) ) return ResponseEntity.badRequest().build();
|
||||
Long id = roomService.createRoom(new Room(players_count, is_private, "0"));
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
Long userId = userService.findByUsername(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername()).getId();
|
||||
roomPlayerService.leaveByUserId(userId);
|
||||
roomPlayerService.joinRoom(id, userId);
|
||||
return ResponseEntity.accepted().build();
|
||||
}
|
||||
|
||||
@PostMapping("/async/notify/get/")
|
||||
@ResponseBody
|
||||
public DeferredResult<LongPollResult> getNotify(@RequestParam("last_chat_id") Long last_chat_id,
|
||||
@RequestParam("accessToken") String accessToken,
|
||||
@RequestParam("uid") Long userId) {
|
||||
@RequestParam("uid") Long userId,
|
||||
@RequestParam("poll_token") String poll_token) {
|
||||
try {
|
||||
User u = userService.findById(userId);
|
||||
if (u == null) return null;
|
||||
@ -145,48 +147,22 @@ public class APIController {
|
||||
} catch ( Exception e ) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
if( poll_token.length() != 32 ) return null;
|
||||
final DeferredResult<LongPollResult> deferredResult = new DeferredResult<>();
|
||||
longPoll.getLongPollingQueue().add(new LongPollingSession(last_chat_id, deferredResult));
|
||||
/*Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
Long userId = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername()).getId();
|
||||
userService.updateOnline(userId);
|
||||
|
||||
Integer onlineCount = userService.countByIsOnline();
|
||||
List<Chat> results = chatService.getAfterLastChatId(last_chat_id);
|
||||
List<UserResult> users = results.stream()
|
||||
.map(Chat::getUserId)
|
||||
.distinct()
|
||||
.map( l -> userService.findById(l) )
|
||||
.map( u -> new UserResult(u.getId(), u.getUsername()) )
|
||||
.collect(Collectors.toList());
|
||||
results = results.stream().map( c -> {
|
||||
String message = c.getMessage();
|
||||
for( int i = 0; i < message.length(); i++ ) {
|
||||
if( message.charAt(i) == '@' ) {
|
||||
int u = message.substring(i).indexOf(' ') + i;
|
||||
String username = message.substring(i+1, u);
|
||||
User user = userService.findByUsername(username);
|
||||
if( user != null ) {
|
||||
Long uid = user.getId();
|
||||
message = message.substring(0, i) + "<a href=\"/profile/" + uid + "\" class=\"chat-history-user\"><span class=\"_nick\">" + username + "</span></a>" + message.substring(u + 1);
|
||||
} else {
|
||||
message = message.substring(0, i) + username + message.substring(u + 1);
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
if( longPoll.getMap().containsKey(userId) ){
|
||||
LongPollConfig c = longPoll.getMap().get(userId);
|
||||
if( !c.getPoll_token().equals(poll_token) ) {
|
||||
c = new LongPollConfig(last_chat_id, new ArrayList<>(), 0, poll_token, new ArrayList<>(), System.currentTimeMillis());
|
||||
longPoll.getLongPollingQueue().removeIf(q -> q.getUserId().longValue() == userId.longValue());
|
||||
}
|
||||
c.setMessage(message);
|
||||
return c;
|
||||
}).collect(Collectors.toList());
|
||||
// Room stuff
|
||||
|
||||
List<Room> rooms = roomService.getAllActive();
|
||||
List<RoomResult> roomResults = rooms.stream()
|
||||
.map( r -> new RoomResult(r.getId(), r.getPlayerCount(), roomPlayerService.findByRoomId(r.getId()).stream()
|
||||
.map(p -> userService.findById(p.getId()))
|
||||
.map(p -> new UserResult(p.getId(), p.getUsername())).collect(Collectors.toList())))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(new LongPollResult(onlineCount, results, users, roomResults));*/
|
||||
c.setLast_chat_id(last_chat_id);
|
||||
c.setSession_pass(0);
|
||||
c.setLastRequest(System.currentTimeMillis());
|
||||
longPoll.getMap().put(userId, c);
|
||||
} else {
|
||||
longPoll.getMap().put(userId, new LongPollConfig(last_chat_id, new ArrayList<>(), 0, poll_token, new ArrayList<>(), System.currentTimeMillis()));
|
||||
}
|
||||
longPoll.getLongPollingQueue().add(new LongPollingSession(userId, deferredResult));
|
||||
return deferredResult;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class StaticController {
|
||||
User u = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername());
|
||||
Long userId = u.getId();
|
||||
String apiKey = Hash.sha256((u.getId() + u.getUsername() + u.getPassword()).getBytes());
|
||||
model.addAttribute("auth_obj", new AuthApiObject(apiKey, userId));
|
||||
model.addAttribute("auth_obj", new AuthApiObject(apiKey, userId, Hash.rnd()));
|
||||
} catch ( Exception e ) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
@ -10,4 +10,5 @@ import lombok.NoArgsConstructor;
|
||||
public class AuthApiObject {
|
||||
private String accessToken;
|
||||
private Long uid;
|
||||
private String poll_token;
|
||||
}
|
||||
|
14
src/main/java/com/alterdekim/game/dto/FriendResult.java
Normal file
14
src/main/java/com/alterdekim/game/dto/FriendResult.java
Normal file
@ -0,0 +1,14 @@
|
||||
package com.alterdekim.game.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
public class FriendResult {
|
||||
private FriendState action;
|
||||
private Long id;
|
||||
private String username;
|
||||
}
|
6
src/main/java/com/alterdekim/game/dto/FriendState.java
Normal file
6
src/main/java/com/alterdekim/game/dto/FriendState.java
Normal file
@ -0,0 +1,6 @@
|
||||
package com.alterdekim.game.dto;
|
||||
|
||||
public enum FriendState {
|
||||
ADD,
|
||||
REMOVE
|
||||
}
|
@ -14,5 +14,6 @@ public class LongPollResult {
|
||||
private Integer onlineCount;
|
||||
private List<Chat> messages;
|
||||
private List<UserResult> users;
|
||||
private List<RoomResult> rooms;
|
||||
private List<RoomResultV2> rooms;
|
||||
private List<FriendResult> friends;
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.alterdekim.game.dto;
|
||||
|
||||
public enum RoomResultState {
|
||||
ADD_CHANGE,
|
||||
REMOVE
|
||||
}
|
17
src/main/java/com/alterdekim/game/dto/RoomResultV2.java
Normal file
17
src/main/java/com/alterdekim/game/dto/RoomResultV2.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.alterdekim.game.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
public class RoomResultV2 {
|
||||
private RoomResultState action;
|
||||
private Long id;
|
||||
private Integer playerCount;
|
||||
private List<UserResult> players;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.alterdekim.game.repository;
|
||||
|
||||
import com.alterdekim.game.entities.FriendStatus;
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface FriendRepository extends JpaRepository<FriendStatus, Long> {
|
||||
@Query(value = "SELECT IF(f.firstUserId = :userId, f.secondUserId, f.firstUserId) FROM FriendStatus f WHERE (f.firstUserId = :userId OR f.secondUserId = :userId) AND f.status = 2")
|
||||
List<Long> getFriendsOfUserId(@Param("userId") Long userId);
|
||||
}
|
@ -3,11 +3,22 @@ package com.alterdekim.game.repository;
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import com.alterdekim.game.entities.RoomPlayer;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RoomPlayerRepository extends JpaRepository<RoomPlayer, Long> {
|
||||
List<RoomPlayer> findByRoomId(Long roomId);
|
||||
|
||||
@Query(value = "SELECT new RoomPlayer(r.id, r.roomId, r.userId) FROM RoomPlayer r WHERE r.roomId = :roomId ORDER BY r.userId ASC")
|
||||
List<RoomPlayer> findByRoomId(@Param("roomId") Long roomId);
|
||||
|
||||
@Transactional
|
||||
@Modifying
|
||||
@Query(value = "DELETE FROM RoomPlayer r WHERE r.userId = :userId")
|
||||
void deleteAllByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -3,14 +3,22 @@ package com.alterdekim.game.repository;
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RoomRepository extends JpaRepository<Room, Long> {
|
||||
|
||||
@Query(value = "SELECT r FROM Room r WHERE r.isPrivate = false")
|
||||
@Query(value = "SELECT r FROM Room r WHERE r.isPrivate = false ORDER BY r.id ASC")
|
||||
List<Room> findAllByActiveTrue();
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
@Modifying
|
||||
@Query(value = "DELETE FROM room WHERE room.id NOT IN (SELECT t.room_id FROM (SELECT COUNT(id) as UID, room_id FROM room_player GROUP BY room_id) t)", nativeQuery = true)
|
||||
void clearEmptyRooms();
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.alterdekim.game.service;
|
||||
|
||||
import com.alterdekim.game.repository.FriendRepository;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class FriendServiceImpl {
|
||||
private final FriendRepository repository;
|
||||
|
||||
public List<Long> getFriendsOfUserId(Long userId) {
|
||||
return repository.getFriendsOfUserId(userId);
|
||||
}
|
||||
}
|
@ -24,4 +24,12 @@ public class RoomPlayerServiceImpl implements RoomPlayerService{
|
||||
public List<RoomPlayer> findByRoomId(Long roomId) {
|
||||
return repository.findByRoomId(roomId);
|
||||
}
|
||||
|
||||
public void joinRoom(Long id, Long userId) {
|
||||
repository.save(new RoomPlayer(id, userId));
|
||||
}
|
||||
|
||||
public void leaveByUserId(Long userId) {
|
||||
repository.deleteAllByUserId(userId);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.alterdekim.game.repository.RoomRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class RoomServiceImpl implements RoomService {
|
||||
@ -22,4 +23,16 @@ public class RoomServiceImpl implements RoomService {
|
||||
public List<Room> getAllActive() {
|
||||
return roomRepository.findAllByActiveTrue();
|
||||
}
|
||||
|
||||
public Optional<Room> findById(Long id) {
|
||||
return roomRepository.findById(id);
|
||||
}
|
||||
|
||||
public Long createRoom(Room room) {
|
||||
return roomRepository.save(room).getId();
|
||||
}
|
||||
|
||||
public void clearEmptyRooms() {
|
||||
roomRepository.clearEmptyRooms();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package com.alterdekim.game.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Hash {
|
||||
public static String sha256( byte[] b ) throws Exception {
|
||||
@ -19,4 +22,12 @@ public class Hash {
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
public static String rnd() {
|
||||
return IntStream.generate(() -> new Random().nextInt(0, 62))
|
||||
.limit(32)
|
||||
.boxed()
|
||||
.map(i -> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".charAt(i)+"")
|
||||
.collect(Collectors.joining());
|
||||
}
|
||||
}
|
||||
|
414
src/main/resources/static/css/games.css
Normal file
414
src/main/resources/static/css/games.css
Normal file
@ -0,0 +1,414 @@
|
||||
.grid {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(12,1fr);
|
||||
grid-column-gap: 25px;
|
||||
}
|
||||
|
||||
.g-col-4 {
|
||||
grid-column-end: span 4;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.g-col-8 {
|
||||
grid-column-end: span 8;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
border-bottom: 2px solid rgba(0,0,0,.1);
|
||||
border-radius: 5px;
|
||||
padding-top: .1px;
|
||||
padding-bottom: .1px;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.block-content {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.market {
|
||||
height: 160px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.transparent-override {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.text-glowing {
|
||||
color: rgba(55, 188, 157, 1) !important;
|
||||
}
|
||||
|
||||
.mission-one {
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid #e9eaec;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.mission-target>span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.mission-block>span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-top: 5px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: rgba(55, 188, 157, 1) !important;
|
||||
}
|
||||
|
||||
.mission-block, .mission-target {
|
||||
font-size: 13px;
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
}
|
||||
|
||||
.mission-text {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.friend-search {
|
||||
margin: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.empty-list-message {
|
||||
text-align: center;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.empty-list-message>p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.title > span {
|
||||
color: #a7adb5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-history {
|
||||
padding: 20px;
|
||||
margin-bottom: 15px;
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#market-carousel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.carousel-title-text {
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.carousel-body-text {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.carousel-item-body {
|
||||
padding: 0 70px;
|
||||
}
|
||||
|
||||
.carousel-item-background {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chat-history-one {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.chat-history-info {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-right: 5px;
|
||||
color: #989aa4;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.chat-history-user {
|
||||
padding: 0 6px;
|
||||
text-decoration: none;
|
||||
background-color: #b9bac1;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.chat-history-user>._nick {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.chat-history-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.chat-history-one>* {
|
||||
font-size: 14px;
|
||||
vertical-align: middle;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.chat-history-info>.time {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
margin: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.games-room-one {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
position: relative;
|
||||
border-top: 1px solid;
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.games-room-one-body {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.games-room-one-body-head {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.games-room-one-body-head-info {
|
||||
flex-grow: 999;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.games-room-one-body-members {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
margin-top: 13px;
|
||||
margin-bottom: 5px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one {
|
||||
position: relative;
|
||||
margin: 0 5px;
|
||||
width: calc(20% - 2 * 5px);
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-nick {
|
||||
margin-top: 5px;
|
||||
height: 21px;
|
||||
text-align: center;
|
||||
line-height: 21px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-nick > a {
|
||||
color: #656d78;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-nick > span {
|
||||
color: #656d78;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
border-radius: 100%;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
background: center/cover no-repeat;
|
||||
font: 50px Ionicons;
|
||||
}
|
||||
|
||||
.games-room-one-body-head-info > ._type > div {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.games-room-one-body-head-info > ._with_wormhole > div {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
._slot_join {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#waiting_list > .title {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#waiting_list > .title > a {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
body.modal-open > :not(.modal) {
|
||||
-webkit-filter: blur(3px);
|
||||
-moz-filter: blur(3px);
|
||||
-o-filter: blur(3px);
|
||||
-ms-filter: blur(3px);
|
||||
filter: blur(3px);
|
||||
}
|
||||
|
||||
.game-creation-modal-modes {
|
||||
background-color: #f7f7f7;
|
||||
flex-shrink: 0;
|
||||
border-radius: 5px 0 0 5px;
|
||||
padding: 10px 15px 10px 10px;
|
||||
width: 250px;
|
||||
overflow: hidden;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.game-creation-modal-block {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
left: -5px;
|
||||
border-radius: 5px;
|
||||
padding: 20px 0;
|
||||
width: 375px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 25px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.game-creation-modal-body {
|
||||
display: flex;
|
||||
position: relative;
|
||||
box-shadow: 0 0 100px rgba(0,0,0,.333);
|
||||
border-radius: 5px;
|
||||
width: 620px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one._regular._selected {
|
||||
background: #8cc152;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one._selected {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one {
|
||||
border-radius: 5px;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one-title {
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one-subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
.game-creation-modal-block-title {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
position: relative;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.game-creation-modal-block-subtitle {
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.form-switch-game {
|
||||
transform: scale(1.2);
|
||||
margin-left: 3.5rem;
|
||||
}
|
||||
|
||||
.form-check-input:checked {
|
||||
background-color: #37bc9d;
|
||||
border-color: #37bc9d;
|
||||
}
|
||||
|
||||
#players-count-range, .players-range-value {
|
||||
margin-left: 20px;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.form-range::-webkit-slider-thumb {
|
||||
background-color: #37bc9d;
|
||||
}
|
||||
|
||||
.reply-button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.friend-one {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.friend-one > span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.friend-one > ion-icon {
|
||||
font-size: 18px;
|
||||
color: #37bc9d;
|
||||
cursor: pointer;
|
||||
}
|
110
src/main/resources/static/css/index.css
Normal file
110
src/main/resources/static/css/index.css
Normal file
@ -0,0 +1,110 @@
|
||||
.navbar-brand-custom {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.navbar-brand-custom:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color: #37bc9d;
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: rgba(255,255,255,.85);
|
||||
color: #37bc9d;
|
||||
border-color: rgba(255,255,255,.85);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #ffffff;
|
||||
border-color: #ffffff;
|
||||
color: #37bc9d;
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background-color: rgba(255, 255, 255,0.25);
|
||||
border-color: rgba(255, 255, 255,0.25);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font: 700 3.5em Montserrat;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.page-title-small {
|
||||
margin-top: .7em;
|
||||
font: 500 1.32em/1.4em Montserrat;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.main-billboard {
|
||||
background-color: #37bc9d;
|
||||
height: 700px;
|
||||
text-align: center;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.main-button {
|
||||
color: #5b5d67;
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
font: 600 1.5rem Montserrat;
|
||||
padding: 0 0.9em;
|
||||
height: 2.1em;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.main-button:hover {
|
||||
color: #5b5d67;
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
border-color: rgba(255, 255, 255, 0.85);
|
||||
font: 600 1.5rem Montserrat;
|
||||
padding: 0 0.9em;
|
||||
height: 2.1em;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.page-main-button {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.page-title-second {
|
||||
margin-top: 1.25em;
|
||||
margin-right: 0px;
|
||||
margin-bottom: 1.25em;
|
||||
margin-left: 0px;
|
||||
font: 700 3.25em Montserrat;
|
||||
color: #26272b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.billboard-img {
|
||||
box-shadow: 0 0 100px rgba(0,0,0,.33);
|
||||
width: 900px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.billboard-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 .4em;
|
||||
font: 700 2em Montserrat;
|
||||
}
|
||||
|
||||
.col_text {
|
||||
font-size: 1.1em;
|
||||
text-align: left;
|
||||
}
|
@ -1,10 +1,119 @@
|
||||
$.fn.pressEnter = function(fn) {
|
||||
var isPollingActive = true;
|
||||
|
||||
function createRoom() {
|
||||
let isprivate = $("#flexSwitchCheckDefault").is(':checked');
|
||||
let playerscnt = $("#players-count-range").val();
|
||||
$.ajax({
|
||||
url: "/api/v1/rooms/create/",
|
||||
data: {
|
||||
is_private: isprivate,
|
||||
players_count: playerscnt
|
||||
},
|
||||
method: "POST"
|
||||
}).done(function(data) {
|
||||
$("#game-creation-menu-modal").modal('hide');
|
||||
});
|
||||
}
|
||||
|
||||
function successPolling(data) {
|
||||
console.log(data);
|
||||
let onlineCount = data.onlineCount;
|
||||
$(".chat-title").find("span").html(onlineCount + " online");
|
||||
let messages = data.messages;
|
||||
let users = data.users;
|
||||
let rooms = data.rooms;
|
||||
let friends = data.friends;
|
||||
if( messages.length > 0 ) {
|
||||
last_chat_id = messages[0].id;
|
||||
}
|
||||
for( let i = 0; i < messages.length; i++ ) {
|
||||
let obj = messages[i];
|
||||
let time = parseTime(obj.createdAt);
|
||||
let username = findUser(users, obj.userId).username;
|
||||
let userid = obj.userId;
|
||||
let msgtext = obj.message;
|
||||
let html = '<div class="chat-history-one"><div class="chat-history-info"><span class="time">'+time+'</span><ion-icon name="arrow-undo-outline" class="reply-button" data-userid="'+userid+'" data-username="'+username+'" onClick="replyButtonClicked(this)"></ion-icon></div><span><span class="chat-history-text chat-history-content-message"><span class="formatter"><a href="/profile/'+userid+'" class="chat-history-user"><span class="_nick">'+username+'</span></a><ion-icon name="remove-outline"></ion-icon><span>'+msgtext+'</span></span></span></span></div>';
|
||||
$(".chat-history").append(html);
|
||||
}
|
||||
for( let i = 0; i < rooms.length; i++ ) {
|
||||
let room = rooms[i];
|
||||
if( room.action == 'ADD_CHANGE' ) {
|
||||
let room_p_html = '';
|
||||
for( let u = 0; u < room.players.length; u++ ) {
|
||||
let room_player = room.players[u];
|
||||
room_p_html += '<div class="games-room-one-body-members-one"><div class="games-room-one-body-members-one-avatar" style="background-image: url("https://i.dogecdn.wtf/7lurfckMFrYXm4gf");"><a href="/profile/'+room_player.id+'"></a><div class="_online"></div></div><div class="games-room-one-body-members-one-nick"><a href="/profile/'+room_player.id+'">'+room_player.username+'</a></div></div>';
|
||||
}
|
||||
for( let u = 0; u < (room.playerCount - room.players.length); u++ ) {
|
||||
room_p_html += '<div class="games-room-one-body-members-one _slot_join"><div class="games-room-one-body-members-one-avatar"><ion-icon name="add-outline" style="color: #656d78;"></ion-icon></div><div class="games-room-one-body-members-one-nick"><span>Join</span></div></div>';
|
||||
}
|
||||
let room_html = '<div class="games-room-one" data-room-id="'+room.id+'"><div class="games-room-one-body"><div class="games-room-one-body-head"><div class="games-room-one-body-head-info"><div class="_type"><div>Game</div></div></div><div class="games-room-one-body-head-actions"></div></div><div class="games-room-one-body-members">'+room_p_html+'</div></div></div>';
|
||||
let has_element = false;
|
||||
$(".games-room-one").each(function() {
|
||||
if( $(this).attr("data-room-id") == room.id ) {
|
||||
$(this).replaceWith(room_html);
|
||||
has_element = true;
|
||||
}
|
||||
});
|
||||
if( !has_element ) {
|
||||
$(".rooms-list").append(room_html);
|
||||
}
|
||||
} else if( room.action == 'REMOVE' ) {
|
||||
$(".games-room-one").each(function() {
|
||||
if( $(this).attr("data-room-id") == room.id ) {
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
for( let i = 0; i < friends.length; i++ ) {
|
||||
let friend = friends[i];
|
||||
if( friend.action == 'ADD' ) {
|
||||
let fr_html = '<div class="friend-one" data-friend-id="'+friend.id+'"><a href="/profile/'+friend.id+'" class="navbar-btn"><img class="navbar-profile-img" src="https://avatars.githubusercontent.com/u/102559365?v=4"></a><span>'+friend.username+'</span><ion-icon name="person-add-outline" role="img" class="md hydrated"></ion-icon></div>';
|
||||
$(".friends-online-list").append(fr_html);
|
||||
} else if( friend.action == 'REMOVE' ) {
|
||||
$(".friend-one").each(function() {
|
||||
if( $(this).attr("data-friend-id") == friend.id ) {
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
var clh = $('#chat_list').find(".chat-history");
|
||||
clh.scrollTop(clh.prop("scrollHeight"));
|
||||
$("#chat_list").find(".chat-history").css("display", "");
|
||||
$("#chat_list").find(".message-input").css("display", "");
|
||||
$("#chat_list").find(".block-content").css("display", "none");
|
||||
}
|
||||
|
||||
function pollServer() {
|
||||
let accessToken = $("api-tag").attr("data-access-token");
|
||||
let uid = $("api-tag").attr("data-uid");
|
||||
let poll_token = $("api-tag").attr("data-poll-token");
|
||||
if (isPollingActive) {
|
||||
window.setTimeout(function () {
|
||||
$.ajax({
|
||||
url: "/async/notify/get/",
|
||||
data: {
|
||||
last_chat_id: last_chat_id,
|
||||
accessToken: accessToken,
|
||||
poll_token: poll_token,
|
||||
uid: uid
|
||||
},
|
||||
method: "POST"
|
||||
}).done(function(data) {
|
||||
successPolling(data);
|
||||
//SUCCESS LOGIC
|
||||
pollServer();
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
$.fn.pressEnter = function(fn) {
|
||||
return this.each(function() {
|
||||
$(this).bind('enterPress', fn);
|
||||
$(this).keyup(function(e){
|
||||
if(e.keyCode == 13)
|
||||
{
|
||||
$(this).keyup(function(e) {
|
||||
if(e.keyCode == 13) {
|
||||
$(this).trigger("enterPress");
|
||||
}
|
||||
})
|
||||
@ -34,41 +143,6 @@ function replyButtonClicked(obj) {
|
||||
$('#chat-message-input').val($('#chat-message-input').val() + " @" + username + "");
|
||||
}
|
||||
|
||||
setInterval(function() {
|
||||
let accessToken = $("api-tag").attr("data-access-token");
|
||||
let uid = $("api-tag").attr("data-uid");
|
||||
$.ajax({
|
||||
url: "/async/notify/get/",
|
||||
data: {
|
||||
last_chat_id: last_chat_id,
|
||||
accessToken: accessToken,
|
||||
uid: uid
|
||||
},
|
||||
method: "GET"
|
||||
}).done(function(data) {
|
||||
console.log(data);
|
||||
let onlineCount = data.onlineCount;
|
||||
$(".chat-title").find("span").html(onlineCount + " online");
|
||||
let messages = data.messages;
|
||||
let users = data.users;
|
||||
if( messages.length > 0 ) {
|
||||
last_chat_id = messages[0].id;
|
||||
}
|
||||
for( let i = 0; i < messages.length; i++ ) {
|
||||
let obj = messages[i];
|
||||
let time = parseTime(obj.createdAt);
|
||||
let username = findUser(users, obj.userId).username;
|
||||
let userid = obj.userId;
|
||||
let msgtext = obj.message;
|
||||
let html = '<div class="chat-history-one"><div class="chat-history-info"><span class="time">'+time+'</span><ion-icon name="arrow-undo-outline" class="reply-button" data-userid="'+userid+'" data-username="'+username+'" onClick="replyButtonClicked(this)"></ion-icon></div><span><span class="chat-history-text chat-history-content-message"><span class="formatter"><a href="/profile/'+userid+'" class="chat-history-user"><span class="_nick">'+username+'</span></a><ion-icon name="remove-outline"></ion-icon><span>'+msgtext+'</span></span></span></span></div>';
|
||||
$(".chat-history").append(html);
|
||||
}
|
||||
$("#chat_list").find(".chat-history").css("display", "");
|
||||
$("#chat_list").find(".message-input").css("display", "");
|
||||
$("#chat_list").find(".block-content").css("display", "none");
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#players-count-range").on("input", function() {
|
||||
$("label[for='players-count-range']").find("span").text($(this).val());
|
||||
@ -86,13 +160,6 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: "/api/v1/games/list",
|
||||
method: "GET"
|
||||
}).done(function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
// block-content
|
||||
|
||||
$.ajax({
|
||||
@ -114,6 +181,8 @@ $(document).ready(function() {
|
||||
let html = '<div class="chat-history-one"><div class="chat-history-info"><span class="time">'+time+'</span><ion-icon name="arrow-undo-outline" class="reply-button" data-userid="'+userid+'" data-username="'+username+'" onClick="replyButtonClicked(this)"></ion-icon></div><span><span class="chat-history-text chat-history-content-message"><span class="formatter"><a href="/profile/'+userid+'" class="chat-history-user"><span class="_nick">'+username+'</span></a><ion-icon name="remove-outline"></ion-icon><span>'+msgtext+'</span></span></span></span></div>';
|
||||
$(".chat-history").append(html);
|
||||
}
|
||||
var clh = $('#chat_list').find(".chat-history");
|
||||
clh.scrollTop(clh.prop("scrollHeight"));
|
||||
$("#chat_list").find(".chat-history").css("display", "");
|
||||
$("#chat_list").find(".message-input").css("display", "");
|
||||
$("#chat_list").find(".block-content").css("display", "none");
|
||||
@ -140,10 +209,8 @@ $(document).ready(function() {
|
||||
$(".market").find("#market-carousel").css("display", "");
|
||||
});
|
||||
|
||||
/*$.ajax({
|
||||
url: "/api/v1/games/list",
|
||||
method: "GET"
|
||||
}).done(function(data) {
|
||||
console.log(data);
|
||||
});*/
|
||||
pollServer();
|
||||
|
||||
$(".rooms-list").css("display", "");
|
||||
$("#waiting_list").find(".block-content").css("display", "none");
|
||||
});
|
@ -2,406 +2,8 @@
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<style>
|
||||
.grid {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(12,1fr);
|
||||
grid-column-gap: 25px;
|
||||
}
|
||||
|
||||
.g-col-4 {
|
||||
grid-column-end: span 4;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.g-col-8 {
|
||||
grid-column-end: span 8;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
border-bottom: 2px solid rgba(0,0,0,.1);
|
||||
border-radius: 5px;
|
||||
padding-top: .1px;
|
||||
padding-bottom: .1px;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 1000px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.block-content {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.market {
|
||||
height: 160px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.transparent-override {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.text-glowing {
|
||||
color: rgba(55, 188, 157, 1) !important;
|
||||
}
|
||||
|
||||
.mission-one {
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid #e9eaec;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.mission-target>span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.mission-block>span {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-top: 5px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: rgba(55, 188, 157, 1) !important;
|
||||
}
|
||||
|
||||
.mission-block, .mission-target {
|
||||
font-size: 13px;
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
}
|
||||
|
||||
.mission-text {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.friend-search {
|
||||
margin: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.empty-list-message {
|
||||
text-align: center;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.empty-list-message>p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.title > span {
|
||||
color: #a7adb5;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chat-history {
|
||||
padding: 20px;
|
||||
margin-bottom: 15px;
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#market-carousel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.carousel-title-text {
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.carousel-body-text {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.carousel-item-body {
|
||||
padding: 0 70px;
|
||||
}
|
||||
|
||||
.carousel-item-background {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chat-history-one {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.chat-history-info {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-right: 5px;
|
||||
color: #989aa4;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.chat-history-user {
|
||||
padding: 0 6px;
|
||||
text-decoration: none;
|
||||
background-color: #b9bac1;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.chat-history-user>._nick {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.chat-history-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.chat-history-one>* {
|
||||
font-size: 14px;
|
||||
vertical-align: middle;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.chat-history-info>.time {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
margin: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.games-room-one {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
position: relative;
|
||||
border-top: 1px solid;
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.games-room-one-body {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.games-room-one-body-head {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.games-room-one-body-head-info {
|
||||
flex-grow: 999;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.games-room-one-body-members {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
margin-top: 13px;
|
||||
margin-bottom: 5px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one {
|
||||
position: relative;
|
||||
margin: 0 5px;
|
||||
width: calc(20% - 2 * 5px);
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-nick {
|
||||
margin-top: 5px;
|
||||
height: 21px;
|
||||
text-align: center;
|
||||
line-height: 21px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-nick > a {
|
||||
color: #656d78;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-nick > span {
|
||||
color: #656d78;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.games-room-one-body-members-one-avatar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
border-radius: 100%;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
background: center/cover no-repeat;
|
||||
font: 50px Ionicons;
|
||||
}
|
||||
|
||||
.games-room-one-body-head-info > ._type > div {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.games-room-one-body-head-info > ._with_wormhole > div {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
._slot_join {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#waiting_list > .title {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#waiting_list > .title > a {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
body.modal-open > :not(.modal) {
|
||||
-webkit-filter: blur(3px);
|
||||
-moz-filter: blur(3px);
|
||||
-o-filter: blur(3px);
|
||||
-ms-filter: blur(3px);
|
||||
filter: blur(3px);
|
||||
}
|
||||
|
||||
.game-creation-modal-modes {
|
||||
background-color: #f7f7f7;
|
||||
flex-shrink: 0;
|
||||
border-radius: 5px 0 0 5px;
|
||||
padding: 10px 15px 10px 10px;
|
||||
width: 250px;
|
||||
overflow: hidden;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.game-creation-modal-block {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
left: -5px;
|
||||
border-radius: 5px;
|
||||
padding: 20px 0;
|
||||
width: 375px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 25px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.game-creation-modal-body {
|
||||
display: flex;
|
||||
position: relative;
|
||||
box-shadow: 0 0 100px rgba(0,0,0,.333);
|
||||
border-radius: 5px;
|
||||
width: 620px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one._regular._selected {
|
||||
background: #8cc152;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one._selected {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one {
|
||||
border-radius: 5px;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one-title {
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.game-creation-modal-modes-one-subtitle {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
opacity: .85;
|
||||
}
|
||||
|
||||
.game-creation-modal-block-title {
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
position: relative;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.game-creation-modal-block-subtitle {
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.form-switch-game {
|
||||
transform: scale(1.2);
|
||||
margin-left: 3.5rem;
|
||||
}
|
||||
|
||||
.form-check-input:checked {
|
||||
background-color: #37bc9d;
|
||||
border-color: #37bc9d;
|
||||
}
|
||||
|
||||
#players-count-range, .players-range-value {
|
||||
margin-left: 20px;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.form-range::-webkit-slider-thumb {
|
||||
background-color: #37bc9d;
|
||||
}
|
||||
|
||||
.reply-button {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<api-tag th:data-access-token="${auth_obj.accessToken}" th:data-uid="${auth_obj.uid}"></api-tag>
|
||||
<link rel="stylesheet" href="/static/css/games.css"/>
|
||||
<api-tag th:data-access-token="${auth_obj.accessToken}" th:data-uid="${auth_obj.uid}" th:data-poll-token="${auth_obj.poll_token}"></api-tag>
|
||||
</head>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/navbar}"></th:block>
|
||||
@ -425,7 +27,7 @@
|
||||
<label class="form-check-label" for="flexSwitchCheckDefault">Private room</label>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: center;">
|
||||
<button class="btn btn-primary navbar-btn">
|
||||
<button class="btn btn-primary navbar-btn" onClick="createRoom()">
|
||||
<span>Start</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -484,15 +86,15 @@
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div>
|
||||
<div class="friends-online-list" style="display: none;">
|
||||
<div class="friend-search">
|
||||
<input type="text" class="friend-search-input form-control" placeholder="Search friends">
|
||||
</div>
|
||||
|
||||
<div class="empty-list-message">
|
||||
<!--<div class="empty-list-message">
|
||||
<p>No friends online.</p>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="g-col-8">
|
||||
@ -559,8 +161,8 @@
|
||||
<ion-icon name="dice-outline"></ion-icon>
|
||||
<span>Create game</span>
|
||||
</a></div>
|
||||
<!--<div class="rooms-list">
|
||||
<div class="games-room-one">
|
||||
<div class="rooms-list" style="display: none">
|
||||
<!--<div class="games-room-one">
|
||||
<div class="games-room-one-body">
|
||||
<div class="games-room-one-body-head">
|
||||
<div class="games-room-one-body-head-info">
|
||||
@ -620,8 +222,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>-->
|
||||
</div>
|
||||
<div class="block-content">
|
||||
<div class="spinner-grow text-glowing" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
|
@ -2,118 +2,7 @@
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<style>
|
||||
.navbar-brand-custom {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.navbar-brand-custom:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color: #37bc9d;
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: rgba(255,255,255,.85);
|
||||
color: #37bc9d;
|
||||
border-color: rgba(255,255,255,.85);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #ffffff;
|
||||
border-color: #ffffff;
|
||||
color: #37bc9d;
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background-color: rgba(255, 255, 255,0.25);
|
||||
border-color: rgba(255, 255, 255,0.25);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font: 700 3.5em Montserrat;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.page-title-small {
|
||||
margin-top: .7em;
|
||||
font: 500 1.32em/1.4em Montserrat;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.main-billboard {
|
||||
background-color: #37bc9d;
|
||||
height: 700px;
|
||||
text-align: center;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.main-button {
|
||||
color: #5b5d67;
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
font: 600 1.5rem Montserrat;
|
||||
padding: 0 0.9em;
|
||||
height: 2.1em;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.main-button:hover {
|
||||
color: #5b5d67;
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
border-color: rgba(255, 255, 255, 0.85);
|
||||
font: 600 1.5rem Montserrat;
|
||||
padding: 0 0.9em;
|
||||
height: 2.1em;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.page-main-button {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.page-title-second {
|
||||
margin-top: 1.25em;
|
||||
margin-right: 0px;
|
||||
margin-bottom: 1.25em;
|
||||
margin-left: 0px;
|
||||
font: 700 3.25em Montserrat;
|
||||
color: #26272b;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.billboard-img {
|
||||
box-shadow: 0 0 100px rgba(0,0,0,.33);
|
||||
width: 900px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.billboard-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0 0 .4em;
|
||||
font: 700 2em Montserrat;
|
||||
}
|
||||
|
||||
.col_text {
|
||||
font-size: 1.1em;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/css/index.css">
|
||||
</head>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/navbar}"></th:block>
|
||||
|
Loading…
x
Reference in New Issue
Block a user