fork download
  1. import SwiftUI
  2.  
  3. struct LeaveHubView: View {
  4. var body: some View {
  5. NavigationStack {
  6. ScrollView {
  7. VStack(spacing: 16) {
  8. // Chat bubble / card
  9. MessageCard()
  10.  
  11. // Quick action grid
  12. QuickActionGrid()
  13. }
  14. .padding(.horizontal)
  15. .padding(.top, 8)
  16. .background(Color(UIColor.systemGroupedBackground))
  17. }
  18. .navigationTitle("LeaveHub")
  19. .navigationBarTitleDisplayMode(.inline)
  20. .toolbar {
  21. ToolbarItem(placement: .topBarLeading) {
  22. HStack(spacing: 8) {
  23. Image(systemName: "chevron.left")
  24. Image(systemName: "shield.fill")
  25. .foregroundStyle(.tint)
  26. }
  27. }
  28. ToolbarItemGroup(placement: .topBarTrailing) {
  29. Image(systemName: "magnifyingglass")
  30. Image(systemName: "list.bullet")
  31. }
  32. }
  33. }
  34. }
  35. }
  36.  
  37. // MARK: - Components
  38.  
  39. private struct MessageCard: View {
  40. var body: some View {
  41. HStack(alignment: .bottom, spacing: 12) {
  42. // Avatar
  43. ZStack {
  44. Circle()
  45. .fill(Color(UIColor.secondarySystemBackground))
  46. Image(systemName: "leaf.circle.fill")
  47. .font(.system(size: 22))
  48. .foregroundStyle(.green)
  49. }
  50. .frame(width: 36, height: 36)
  51.  
  52. // Bubble
  53. VStack(alignment: .leading, spacing: 12) {
  54. VStack(spacing: 16) {
  55. // Logo + title
  56. VStack(spacing: 8) {
  57. Image(systemName: "leaf.fill")
  58. .font(.system(size: 28, weight: .semibold))
  59. .foregroundStyle(.green)
  60.  
  61. Text("LEAVE HUB")
  62. .font(.system(.headline, design: .rounded))
  63. .tracking(1)
  64.  
  65. Text("ขออภัยค่ะ")
  66. .font(.system(.title3, weight: .semibold))
  67. }
  68.  
  69. VStack(alignment: .center, spacing: 6) {
  70. Text("ท่านได้ลงทะเบียนเรียบร้อยแล้วค่ะ")
  71. .font(.body)
  72. Divider()
  73. Text("ภายใต้ชื่อ Test2 ของ Demo")
  74. .font(.body)
  75. Text("Leavehub เรียบร้อยแล้วค่ะ")
  76. .font(.body)
  77. Divider()
  78. Text("ท่านสามารถแจ้งความประสงค์การลา")
  79. .font(.body)
  80. Text("ได้ในช่องทางนี้ได้เลยค่ะ")
  81. .font(.body)
  82. }
  83. .multilineTextAlignment(.center)
  84.  
  85. Button(action: {}) {
  86. Text("แจ้งการลา")
  87. .font(.system(.headline))
  88. .frame(maxWidth: .infinity)
  89. .padding(.vertical, 12)
  90. }
  91. .buttonStyle(.borderedProminent)
  92. .tint(.green)
  93. .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
  94. }
  95. .padding(16)
  96. .background(
  97. RoundedRectangle(cornerRadius: 16, style: .continuous)
  98. .fill(Color(UIColor.systemBackground))
  99. )
  100. .overlay(
  101. RoundedRectangle(cornerRadius: 16, style: .continuous)
  102. .stroke(Color(UIColor.separator), lineWidth: 0.5)
  103. )
  104.  
  105. Text("11:53 AM")
  106. .font(.footnote)
  107. .foregroundStyle(.secondary)
  108. .padding(.top, 4)
  109. .frame(maxWidth: .infinity, alignment: .trailing)
  110. }
  111. }
  112. .padding(.trailing) // like a chat layout
  113. }
  114. }
  115.  
  116. private struct QuickActionGrid: View {
  117. let items: [QuickItem] = [
  118. .init(title: "ลงทะเบียน", subtitle: "ตรวจสอบ วันลา", systemImage: "checklist"),
  119. .init(title: "แจ้งการลา", subtitle: "", systemImage: "laptopcomputer"),
  120. .init(title: "ตรวจสอบ วันหยุด", subtitle: "", systemImage: "calendar"),
  121. .init(title: "ขอสลับวันหยุด", subtitle: "", systemImage: "calendar.badge.exclamationmark")
  122. ]
  123.  
  124. var body: some View {
  125. VStack(spacing: 12) {
  126. LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 12), count: 2), spacing: 12) {
  127. ForEach(items) { item in
  128. VStack(alignment: .leading, spacing: 8) {
  129. HStack {
  130. Image(systemName: item.systemImage)
  131. .font(.system(size: 28))
  132. Spacer()
  133. }
  134. Text(item.title)
  135. .font(.system(.title3, weight: .semibold))
  136. if !item.subtitle.isEmpty {
  137. Text(item.subtitle)
  138. .font(.footnote)
  139. .foregroundStyle(.secondary)
  140. }
  141. Spacer(minLength: 0)
  142. }
  143. .padding(14)
  144. .frame(height: 140)
  145. .background(
  146. RoundedRectangle(cornerRadius: 14, style: .continuous)
  147. .fill(Color(UIColor.systemBackground))
  148. )
  149. .overlay(
  150. RoundedRectangle(cornerRadius: 14, style: .continuous)
  151. .stroke(Color(UIColor.separator), lineWidth: 0.5)
  152. )
  153. }
  154. }
  155. .padding(.bottom, 8)
  156.  
  157. // Bottom app label (like the “LeaveHub ▾” bar in your screenshot)
  158. HStack {
  159. Image(systemName: "ellipsis.rectangle")
  160. Text("LeaveHub")
  161. .font(.body)
  162. Image(systemName: "chevron.down")
  163. Spacer()
  164. }
  165. .padding(.vertical, 10)
  166. .padding(.horizontal, 14)
  167. .background(.ultraThinMaterial, in: Capsule())
  168. }
  169. }
  170. }
  171.  
  172. private struct QuickItem: Identifiable {
  173. let id = UUID()
  174. let title: String
  175. let subtitle: String
  176. let systemImage: String
  177. }
  178.  
  179. // MARK: - Preview
  180.  
  181. #Preview {
  182. LeaveHubView()
  183. }
  184.  
Success #stdin #stdout 0.03s 25988KB
stdin
Standard input is empty
stdout
import SwiftUI

struct LeaveHubView: View {
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 16) {
                    // Chat bubble / card
                    MessageCard()

                    // Quick action grid
                    QuickActionGrid()
                }
                .padding(.horizontal)
                .padding(.top, 8)
                .background(Color(UIColor.systemGroupedBackground))
            }
            .navigationTitle("LeaveHub")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    HStack(spacing: 8) {
                        Image(systemName: "chevron.left")
                        Image(systemName: "shield.fill")
                            .foregroundStyle(.tint)
                    }
                }
                ToolbarItemGroup(placement: .topBarTrailing) {
                    Image(systemName: "magnifyingglass")
                    Image(systemName: "list.bullet")
                }
            }
        }
    }
}

// MARK: - Components

private struct MessageCard: View {
    var body: some View {
        HStack(alignment: .bottom, spacing: 12) {
            // Avatar
            ZStack {
                Circle()
                    .fill(Color(UIColor.secondarySystemBackground))
                Image(systemName: "leaf.circle.fill")
                    .font(.system(size: 22))
                    .foregroundStyle(.green)
            }
            .frame(width: 36, height: 36)

            // Bubble
            VStack(alignment: .leading, spacing: 12) {
                VStack(spacing: 16) {
                    // Logo + title
                    VStack(spacing: 8) {
                        Image(systemName: "leaf.fill")
                            .font(.system(size: 28, weight: .semibold))
                            .foregroundStyle(.green)

                        Text("LEAVE HUB")
                            .font(.system(.headline, design: .rounded))
                            .tracking(1)

                        Text("ขออภัยค่ะ")
                            .font(.system(.title3, weight: .semibold))
                    }

                    VStack(alignment: .center, spacing: 6) {
                        Text("ท่านได้ลงทะเบียนเรียบร้อยแล้วค่ะ")
                            .font(.body)
                        Divider()
                        Text("ภายใต้ชื่อ Test2 ของ Demo")
                            .font(.body)
                        Text("Leavehub เรียบร้อยแล้วค่ะ")
                            .font(.body)
                        Divider()
                        Text("ท่านสามารถแจ้งความประสงค์การลา")
                            .font(.body)
                        Text("ได้ในช่องทางนี้ได้เลยค่ะ")
                            .font(.body)
                    }
                    .multilineTextAlignment(.center)

                    Button(action: {}) {
                        Text("แจ้งการลา")
                            .font(.system(.headline))
                            .frame(maxWidth: .infinity)
                            .padding(.vertical, 12)
                    }
                    .buttonStyle(.borderedProminent)
                    .tint(.green)
                    .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
                }
                .padding(16)
                .background(
                    RoundedRectangle(cornerRadius: 16, style: .continuous)
                        .fill(Color(UIColor.systemBackground))
                )
                .overlay(
                    RoundedRectangle(cornerRadius: 16, style: .continuous)
                        .stroke(Color(UIColor.separator), lineWidth: 0.5)
                )

                Text("11:53 AM")
                    .font(.footnote)
                    .foregroundStyle(.secondary)
                    .padding(.top, 4)
                    .frame(maxWidth: .infinity, alignment: .trailing)
            }
        }
        .padding(.trailing) // like a chat layout
    }
}

private struct QuickActionGrid: View {
    let items: [QuickItem] = [
        .init(title: "ลงทะเบียน", subtitle: "ตรวจสอบ วันลา", systemImage: "checklist"),
        .init(title: "แจ้งการลา", subtitle: "", systemImage: "laptopcomputer"),
        .init(title: "ตรวจสอบ วันหยุด", subtitle: "", systemImage: "calendar"),
        .init(title: "ขอสลับวันหยุด", subtitle: "", systemImage: "calendar.badge.exclamationmark")
    ]

    var body: some View {
        VStack(spacing: 12) {
            LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 12), count: 2), spacing: 12) {
                ForEach(items) { item in
                    VStack(alignment: .leading, spacing: 8) {
                        HStack {
                            Image(systemName: item.systemImage)
                                .font(.system(size: 28))
                            Spacer()
                        }
                        Text(item.title)
                            .font(.system(.title3, weight: .semibold))
                        if !item.subtitle.isEmpty {
                            Text(item.subtitle)
                                .font(.footnote)
                                .foregroundStyle(.secondary)
                        }
                        Spacer(minLength: 0)
                    }
                    .padding(14)
                    .frame(height: 140)
                    .background(
                        RoundedRectangle(cornerRadius: 14, style: .continuous)
                            .fill(Color(UIColor.systemBackground))
                    )
                    .overlay(
                        RoundedRectangle(cornerRadius: 14, style: .continuous)
                            .stroke(Color(UIColor.separator), lineWidth: 0.5)
                    )
                }
            }
            .padding(.bottom, 8)

            // Bottom app label (like the “LeaveHub ▾” bar in your screenshot)
            HStack {
                Image(systemName: "ellipsis.rectangle")
                Text("LeaveHub")
                    .font(.body)
                Image(systemName: "chevron.down")
                Spacer()
            }
            .padding(.vertical, 10)
            .padding(.horizontal, 14)
            .background(.ultraThinMaterial, in: Capsule())
        }
    }
}

private struct QuickItem: Identifiable {
    let id = UUID()
    let title: String
    let subtitle: String
    let systemImage: String
}

// MARK: - Preview

#Preview {
    LeaveHubView()
}