| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import SwiftUI
- struct GrammarCheckerView: View {
- @StateObject private var viewModel = GrammarCheckerViewModel()
- var body: some View {
- ScrollView(.vertical, showsIndicators: false) {
- VStack(alignment: .leading, spacing: 0) {
- header
- .padding(.bottom, 28)
- contentCard
- .padding(.bottom, 24)
- GradientButton(title: "Check Grammar") {
- viewModel.checkGrammar()
- }
- }
- .frame(maxWidth: .infinity, alignment: .topLeading)
- .padding(.horizontal, AppTheme.contentPadding)
- .padding(.top, 32)
- .padding(.bottom, 40)
- }
- .onChange(of: viewModel.text) { newValue in
- if newValue.count > GrammarCheckerViewModel.maxCharacters {
- viewModel.text = String(newValue.prefix(GrammarCheckerViewModel.maxCharacters))
- }
- }
- }
- private var header: some View {
- HStack(alignment: .top) {
- VStack(alignment: .leading, spacing: 8) {
- Text("Grammar Checker")
- .font(.system(size: 30, weight: .bold))
- .foregroundStyle(AppTheme.textPrimary)
- HStack(spacing: 0) {
- Text("Write ")
- .foregroundStyle(AppTheme.textSecondary)
- Text("better")
- .fontWeight(.semibold)
- .foregroundStyle(AppTheme.teal)
- Text(". Sound ")
- .foregroundStyle(AppTheme.textSecondary)
- Text("smarter")
- .fontWeight(.semibold)
- .foregroundStyle(AppTheme.teal)
- Text(".")
- .foregroundStyle(AppTheme.textSecondary)
- }
- .font(.system(size: 15))
- }
- Spacer()
- IconButton(iconName: "gearshape") {}
- }
- }
- private var contentCard: some View {
- VStack(alignment: .leading, spacing: 16) {
- Image("YourContentLogo")
- .resizable()
- .scaledToFit()
- .frame(height: 48)
- .accessibilityLabel("Your Content")
- ZStack(alignment: .bottomTrailing) {
- ThinCaretTextEditor(text: $viewModel.text)
- .font(.system(size: 14))
- .foregroundStyle(AppTheme.textPrimary)
- .padding(14)
- .frame(minHeight: 320)
- .background(Color.white)
- .clipShape(RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius))
- .overlay(
- RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
- .stroke(AppTheme.inputBorder, lineWidth: 1)
- )
- .overlay(alignment: .topLeading) {
- if viewModel.text.isEmpty {
- Text("Type or paste your text here and press the check button...")
- .font(.system(size: 14))
- .foregroundStyle(AppTheme.textMuted)
- .padding(.horizontal, 18)
- .padding(.vertical, 22)
- .allowsHitTesting(false)
- }
- }
- Text(viewModel.characterCountLabel)
- .font(.system(size: 11))
- .foregroundStyle(AppTheme.textMuted)
- .padding(.trailing, 16)
- .padding(.bottom, 12)
- }
- HStack(spacing: 8) {
- ToolbarButton(title: "Paste Text", iconName: "doc.on.clipboard") {
- viewModel.pasteText()
- }
- ToolbarButton(title: "Upload File", iconName: "square.and.arrow.up") {}
- HStack(spacing: 6) {
- Image(systemName: "textformat")
- .font(.system(size: 12))
- Text(viewModel.wordCountLabel)
- .font(.system(size: 12, weight: .medium))
- }
- .foregroundStyle(AppTheme.textSecondary)
- .padding(.horizontal, 12)
- .padding(.vertical, 7)
- .background(Color.white)
- .clipShape(RoundedRectangle(cornerRadius: 8))
- .overlay(
- RoundedRectangle(cornerRadius: 8)
- .stroke(AppTheme.border, lineWidth: 1)
- )
- Spacer()
- IconButton(iconName: "eraser") {
- viewModel.clearText()
- }
- }
- }
- .padding(22)
- .background(AppTheme.cardBackground)
- .clipShape(RoundedRectangle(cornerRadius: AppTheme.cardCornerRadius))
- .shadow(color: AppTheme.cardShadow, radius: 16, y: 6)
- }
- }
|