finish first version of World list page
This commit is contained in:
1 parent
844c4d7587
commit
2e4dfa48cd
7 files changed
+183
-10
No files matched your search
@@ -9,11 +9,40 @@ import SwiftUI
|
||||
|
||||
struct WorldCardView : View {
|
||||
var world : World
|
||||
var isSelected = false
|
||||
|
||||
var body : some View {
|
||||
VStack {
|
||||
Text(world.name)
|
||||
ZStack(alignment: .bottom) {
|
||||
LinearGradient(
|
||||
colors: [.clear, .black.opacity(0.5)],
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
|
||||
HStack(alignment: .bottom) {
|
||||
Text(world.name)
|
||||
.foregroundStyle(.white)
|
||||
.font(.headline)
|
||||
|
||||
Spacer()
|
||||
|
||||
if isSelected {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.font(.system(size: 28))
|
||||
.foregroundStyle(.white, .indigo)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, 4)
|
||||
|
||||
}
|
||||
.background(.red)
|
||||
.frame(height: 220)
|
||||
.background {
|
||||
Image(systemName: "globe.europe.africa")
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.contentShape(RoundedRectangle(cornerRadius: 20))
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -23,4 +23,13 @@ class World {
|
||||
self.createdAt = Date()
|
||||
self.updatedAt = Date()
|
||||
}
|
||||
|
||||
func duplicate() -> World {
|
||||
let newWorld = World(
|
||||
name: self.name, overview: self.overview
|
||||
)
|
||||
|
||||
return newWorld
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,9 +20,6 @@ struct WorldListHeaderView : View {
|
||||
)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
}
|
||||
.padding(.vertical, 50)
|
||||
.padding(.horizontal, 10)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// WorldListAreaInsetModifier.swift
|
||||
// WorldBuilder
|
||||
//
|
||||
// Created by Giovanni Josserand on 03/09/2026.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct WorldListAreaInsetModifier : ViewModifier {
|
||||
let isSelecting : Bool
|
||||
@Binding var selectedWorlds : Set<World.ID>
|
||||
let worlds : [World]
|
||||
|
||||
@Environment(\.modelContext) private var context
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.safeAreaInset(edge: .bottom){
|
||||
if isSelecting && !selectedWorlds.isEmpty {
|
||||
HStack {
|
||||
let worldsToAction = worlds.filter { world in
|
||||
selectedWorlds.contains(world.id)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
for world in worldsToAction {
|
||||
context.insert(world.duplicate())
|
||||
}
|
||||
} label: {
|
||||
Label("Dupliquer", systemImage: "plus.square.on.square")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(role: .destructive){
|
||||
for world in worldsToAction {
|
||||
context.delete(world)
|
||||
}
|
||||
}label : {
|
||||
Label("Supprimer", systemImage: "trash")
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// WorldListToolbarView.swift
|
||||
// WorldBuilder
|
||||
//
|
||||
// Created by Giovanni Josserand on 03/09/2026.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct WorldListToolbarModifier : ViewModifier {
|
||||
@Binding var isSelecting : Bool
|
||||
@Binding var selectedWorlds : Set<World.ID>
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.toolbar{
|
||||
ToolbarItem(placement: .topBarLeading) {
|
||||
if isSelecting {
|
||||
Button("Annuler") {
|
||||
selectedWorlds.removeAll()
|
||||
isSelecting = false
|
||||
}
|
||||
} else {
|
||||
Button("Sélectionner") {
|
||||
isSelecting = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
if !isSelecting {
|
||||
NavigationLink {
|
||||
CreateWorldView()
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,10 @@ struct WorldListView: View {
|
||||
@Query(sort: \World.createdAt, order: .reverse)
|
||||
private var worlds: [World]
|
||||
let columns = [GridItem(.flexible()), GridItem(.flexible())]
|
||||
|
||||
@State private var isSelecting = false
|
||||
@State private var selectedWorlds = Set<World.ID>()
|
||||
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
@@ -24,16 +28,58 @@ struct WorldListView: View {
|
||||
}else{
|
||||
LazyVGrid(columns: columns){
|
||||
ForEach(worlds) {world in
|
||||
NavigationLink{
|
||||
WorldOverviewView()
|
||||
} label: {
|
||||
WorldCardView(world: world)
|
||||
if isSelecting {
|
||||
WorldCardView(
|
||||
world: world,
|
||||
isSelected: selectedWorlds.contains(world.id)
|
||||
)
|
||||
.onTapGesture {
|
||||
if selectedWorlds.contains(world.id) {
|
||||
selectedWorlds.remove(world.id)
|
||||
} else {
|
||||
selectedWorlds.insert(world.id)
|
||||
}
|
||||
}
|
||||
|
||||
}else {
|
||||
NavigationLink{
|
||||
WorldOverviewView()
|
||||
} label: {
|
||||
WorldCardView(world: world)
|
||||
}
|
||||
.contextMenu{
|
||||
Button {
|
||||
context.insert(world.duplicate())
|
||||
} label: {
|
||||
Label("Dupliquer", systemImage: "plus.square.on.square")
|
||||
}
|
||||
|
||||
Button(role: .destructive){
|
||||
context.delete(world)
|
||||
}label : {
|
||||
Label("Supprimer", systemImage: "trash")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.frame(maxHeight: .infinity, alignment: .topLeading)
|
||||
.modifier(
|
||||
WorldListAreaInsetModifier(
|
||||
isSelecting: isSelecting,
|
||||
selectedWorlds: $selectedWorlds,
|
||||
worlds: worlds
|
||||
)
|
||||
)
|
||||
}
|
||||
.modifier(
|
||||
WorldListToolbarModifier(
|
||||
isSelecting: $isSelecting,
|
||||
selectedWorlds: $selectedWorlds
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user